ugrás a tartalomhoz

Hogyan lehet nullát visszaadni az SQL-ben

misike · 2021. Ápr. 18. (V), 17.20
Üdv!

Egyszerű feladattal nem boldogulok. Láttam sok kódot a Neten, de nem tudtam megoldani.
Mysql adatbázisban van egy matek táblám, benne egy "mego" (varchar) oszlop melyben 'jó' vagy 'rossz' értékek vannak. Ugyanebben a táblában van még "ido" (datetime) oszlop melyben a megoldás ideje van tárolva /2020-09-01 06:59:21/ formában. Van még id int(5) azonosító.

Szeretném kilistázni adott id azonosítójú felhasználó elmúlt 7 napi megoldásainak a számát.
Nem tudom kiíratni a 0 számot.

Próbálkoztam, de nem sikerült.

SELECT
SUM(CASE WHEN mego='Jó' THEN 1 ELSE 0 END) AS jo
FROM matek
where'$id' = id
group by DATE(ido) ORDER BY ido desc Limit 7
 
1

where'$id' = id Ezt

Poetro · 2021. Ápr. 18. (V), 17.27
where'$id' = id

Ezt részleteznéd, hogy mit akar jelenteni?
3

A kívánt felhasználó id-ja

misike · 2021. Ápr. 18. (V), 17.46
A kívánt felhasználó id-ja
2

Valami olyan, hogy Select

mind1 valami név · 2021. Ápr. 18. (V), 17.31
Valami olyan, hogy
Select count(*) from matek group by date(ido) having mego="Jó" ...


nem segít?
Jó rég volt, nem vállalok felelősséget érte! ;)
4

Pontatlan voltam. El kellene

misike · 2021. Ápr. 18. (V), 17.56
Pontatlan voltam.
El kellene tenni egy változóba a kapott értéket. Diagram lesz belőle.
5

Szerintem a sum(when felt

mind1 valami név · 2021. Ápr. 18. (V), 18.09
Szerintem a sum(when felt then 1 else 0) ... group by ...
és a count(*) ... group by ... having felt ... azonos eredményt kellene, hogy adjon, de nem szintaktikai gondod van?

Nem sum(case mego when 'Jó' then 1 else 0 end) a helyes szintaxis?
6

Amit írtál az lefut csak nem

misike · 2021. Ápr. 18. (V), 18.35
Amit írtál az lefut csak nem adja ki a 0-t.

Itt is láttam hasonlót, meg még máshol is.
7

Innen kezdve szinte szó

mind1 valami név · 2021. Ápr. 18. (V), 18.51
Innen kezdve szinte szó szerint vak vezet vilagtalant :)
Én valaha Oracle-lel dolgoztam, de már abból sincs sok emlékem, mysql-ről meg csak a sok évvel ezelőtti tutorialok maradéka.
Ha az lefut, amit írtam, akkor két dolog kérdéses:
1. A tiéd mit tesz helyette, mert a linkelt példád szerint szintaktikailag az is OK.
2. Az enyém mit csinál rosszul? Miből gondolod, hogy nem adja ki a 0-t?

Kicsit egyszerűbb lenne, ha mutatnál logokat a futásról, eredményekkel, hibaüzenetekkel.
8

Kiiratom a jo változó

misike · 2021. Ápr. 18. (V), 18.57
Kiiratom a jo változó értékét. Ugyan az mint az enyém: 
Jó= 2 Jó= 7 Jó= 8 Jó= 4 Jó= 8 Jó= 12 Jó= 22
Kimaradnak a nullák.
9

Az adatbázisban lévő

misike · 2021. Ápr. 18. (V), 19.04
Az adatbázisban lévő adatokkal dolgozik. Az üres napokon amikor nincs bejegyzés azt kellene nullával kiírnia.

Mint itt

Bocs ha félreérthető voltam.
10

Ja... Hát nem pont ezt

mind1 valami név · 2021. Ápr. 18. (V), 19.16
Ja... Hát nem pont ezt kérdezted... :)
Hiányzó sorokat szerintem nem fog neked pótolni semmi.
De elnézve a hivatkozott posztot, nagy tétben nem fogadnék erre.
11

A korábbi link szerin null-t

misike · 2021. Ápr. 18. (V), 19.18
A korábbi link szerin null-t ír ki.
A 3. válasz szerint lehet. (vagy tévedek?)
12

Bocs, képtelen vagyok teljes

mind1 valami név · 2021. Ápr. 18. (V), 20.09
Bocs, képtelen vagyok teljes alapossággal átrágni magam rajta és vagy valami úgy működik a mysql-ben, ahogy még más rdbms alatt nem láttam és egyesével generálja a napokat, vagy pusztán arról van szó, hogy az adatbázis tartalmazza az összes napot, csak amikor a where-ben megadott feltétel nem teljesül az adott dátumot tartalmazó sorok egyikére sem, akkor nem adott vissza eredményt az eredeti lekérdezés és arra ad vissza NULL-t az új.

Azért majd később ranezek, hátha látok benne valami egyebet is. (Egyáltalán az mysql?)


Update: pardon, ez a hülye mobilos böngésző pont a lényeget vágta le a példából... Továbbra is feltételezd, hogy hülyeségeket beszélek, de...
Amikor a feltétel a WHERE-ben van, akkor a szerver csak azokat a sorokat veszi figyelembe, amelyek megfelelnek a feltételnek. Ha olyan van a WHERE-ben, ami érvényes minden napról legalább egy sorra és a count-ba teszed azt a CASE-t, akkor minden napra kapsz (legalább) egy eredménysort, a count viszont csak azokat számolja, ahol a beleírt érték - itt a CASE által visszaadott érték - nem NULL.
Nem tudom, ez így érthető?
Érzésem szerint az a különbség, hogy nálad talán eleve hiányoznak bizonyos napok az adatbázisból... De csak tipp.
13

Csak megértetem magam.

misike · 2021. Ápr. 19. (H), 09.36
Csak megértetem magam.
Amikor van jó vagy rossz megoldás az bekerül az adatbázisba. Amikor nincs munkavégzés akkor nincs adat arról a napról. A diagramban itt nullát kéne ábrázolnom.

A jó megoldások számát akarom ábrázolni diagramban. Ha nem dolgozott nincs adat a kimaradt napokon. Nincs mit ábrázolni, ez lenne a nulla.
14

Ezt (hangsúlyozom, szerintem)

mind1 valami név · 2021. Ápr. 19. (H), 10.40
Ezt (hangsúlyozom, szerintem) nem tudod megoldani adatbázisból.
Minimum egy tárolt eljárás kell, ami végigpörgeti a napokat, minden egyes naphoz lekéri az aznapi adatokat és amelyikhez nincs adat, arra nullát mutat.
De mondom: szerintem így van. Hogy azóta mennyire változtak a dolgok, mióta én néztem... Passz.
15

Köszi mindent.

misike · 2021. Ápr. 19. (H), 13.26
Köszi mindent.
16

SQLFiddle

Endyl · 2021. Ápr. 19. (H), 16.25
Ha SQLFiddle-ben öszeraknál példa táblát példa adatokkal, akkor könnyebb lenne segíteni.

De ha NULL értékek okoznak problémát, akkor a COALESCE() függvény a barátod.
17

CREATE TABLE `matek` ( `id`

misike · 2021. Ápr. 19. (H), 18.34
CREATE TABLE `matek` (
`id` int(5) NOT NULL,
`ido` datetime NOT NULL,
`mego` varchar(5) CHARACTER SET utf8 COLLATE utf8_hungarian_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `matek` ( `id`, `ido`, `mego`) VALUES
(26, '2020-09-01 19:31:01', 'Jó'),
(26, '2020-09-01 19:31:05', 'Jó'),
(26, '2020-09-03 14:24:52', 'Jó'),
( 5, '2020-09-03 14:25:02', 'Jó');

Ha kiválasztom a id=26 azonosítóval rendelkező felhasználót, akkor
2020-09-01 napra kettőt kell kapni,
2020-09-02 nincs bejegyzés, itt nullát kell kapni,
2020-09-03 napra egyet kell kapni
18

Inkább alkalmazás oldal

Endyl · 2021. Ápr. 19. (H), 21.46
Azt hozzátenném, hogy a hiányzó adatokat érdemesebb alkalmazás oldalról kipótolni nullákkal. De ha mindekép SQL kell, akkor pl. ez működik:

SELECT
    qt.nap,
    SUM(CASE WHEN mego='Jó' THEN 1 ELSE 0 END) AS jo
FROM (
    SELECT DATE_SUB(curdate(), INTERVAL 1 day) AS nap UNION 
    SELECT DATE_SUB(curdate(), INTERVAL 2 day) AS nap UNION 
    SELECT DATE_SUB(curdate(), INTERVAL 3 day) AS nap UNION 
    SELECT DATE_SUB(curdate(), INTERVAL 4 day) AS nap UNION 
    SELECT DATE_SUB(curdate(), INTERVAL 5 day) AS nap UNION 
    SELECT DATE_SUB(curdate(), INTERVAL 6 day) AS nap UNION 
    SELECT DATE_SUB(curdate(), INTERVAL 7 day) AS nap
) AS qt
LEFT JOIN
    matek m
    ON qt.nap=DATE(m.ido)
WHERE
    (id=26 OR id IS NULL)
GROUP BY
    DATE(qt.nap)
ORDER BY
    qt.nap ASC
;
A curdate() helyett megfelelő paramétert beadva bármilyen dátum lekérdezhető.
23

Tökéletes. Köszönöm a

misike · 2021. Ápr. 21. (Sze), 14.52
Van benne hiba. Kihagy napokat.
20

Törölve

misike · 2021. Ápr. 21. (Sze), 07.52
Törölve
21

Kimaradnak napok. pl. Ezekre

misike · 2021. Ápr. 21. (Sze), 07.53
Kimaradnak napok.

pl. Ezekre az adatokra:
CREATE TABLE `matek3` (
`id` int(5) NOT NULL,
`ido` datetime NOT NULL,
`mego` varchar(5) CHARACTER SET utf8 COLLATE utf8_hungarian_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `matek3` ( `id`, `ido`, `mego`) VALUES
(26, '2021-04-15 19:31:01', 'Jó'),
(26, '2021-04-18 19:31:05', 'Jó'),
(26, '2021-04-18 14:24:52', 'Jó'),
( 5, '2021-04-18 14:25:02', 'Jó');

Ezzel a kóddal:
SELECT
qt.nap,
SUM(CASE WHEN mego='Jó' THEN 1 ELSE 0 END) AS jo
FROM (
SELECT DATE_SUB(curdate(), INTERVAL 0 day) AS nap UNION
SELECT DATE_SUB(curdate(), INTERVAL 1 day) AS nap UNION
SELECT DATE_SUB(curdate(), INTERVAL 2 day) AS nap UNION
SELECT DATE_SUB(curdate(), INTERVAL 3 day) AS nap UNION
SELECT DATE_SUB(curdate(), INTERVAL 4 day) AS nap UNION
SELECT DATE_SUB(curdate(), INTERVAL 5 day) AS nap UNION
SELECT DATE_SUB(curdate(), INTERVAL 6 day) AS nap UNION
SELECT DATE_SUB(curdate(), INTERVAL 7 day) AS nap UNION
SELECT DATE_SUB(curdate(), INTERVAL 8 day) AS nap UNION
SELECT DATE_SUB(curdate(), INTERVAL 9 day) AS nap UNION
SELECT DATE_SUB(curdate(), INTERVAL 10 day) AS nap
) AS qt
LEFT JOIN
matek3 m
ON qt.nap=DATE(m.ido)
WHERE
(id=23 OR id IS NULL)
GROUP BY
DATE(qt.nap)
ORDER BY
qt.nap ASC

Ezt az eredményt adja:
2021-04-11 Jó= 0
2021-04-12 Jó= 0
2021-04-13 Jó= 0
2021-04-14 Jó= 0
2021-04-16 Jó= 0
2021-04-17 Jó= 0
2021-04-19 Jó= 0
2021-04-20 Jó= 0
2021-04-21 Jó= 0



Az (id=5 OR id IS NULL) esetén kimarad a 2021-04-15.

Mit csinálok rosszul?
24

Az önálló feltételt csapd

kuka · 2021. Ápr. 21. (Sze), 15.07
Az önálló feltételt csapd hozzá a kapcsolat feltételéhez. Azaz cseréld

LEFT JOIN
matek3 m
ON qt.nap=DATE(m.ido)
WHERE -- <<< EZT <<<
(id=23 OR id IS NULL)
LEFT JOIN
matek3 m
ON qt.nap=DATE(m.ido)
AND -- <<< ERRE <<<
(id=23 OR id IS NULL)
27

Így már jó. Köszi újra.

misike · 2021. Ápr. 21. (Sze), 19.10
Így már jó.
Köszi újra.
19

A 3. válasz szerint lehet.

kuka · 2021. Ápr. 20. (K), 03.28
A 3. válasz szerint lehet. (vagy tévedek?)
SE-n a válaszok sorrendje változtatható. Amiért nálad 3. attól másnál még lehet más. De gondolom Nathan Foley válaszára utaltál. Amely helyes. Ráadásul Vladimir Baranov válasza részben meg is valósítja. A különbség, hogy abban az esetben dátum+hordozó párosról volt szó, melyből a dátum számára létrehoztak egy táblát az összes szóba jöhető dátummal és a CTE csak a párokat generálta.

Viszont a te esetedben magát a dátum intervallumot kell generálni, ami CTE-vel így néz ki:

with recursive qt(nap) as (
    select
    current_date

    union all
    
    select
    date_sub(nap, interval 1 day)

    from qt

    where datediff(current_date, nap) < 6
)
select
*

from qt
De rekurzív CTE esetében inkább bevetnek egy számlálót, mert egész számokkal általában gyorsabbak a műveletek (bár ennyinél úgysem vevödik észre):

with recursive qt(szam, nap) as (
    select
    0, current_date

    union all
    
    select
    szam + 1, date_sub(nap, interval 1 day)

    from qt

    where szam < 6
)
select
nap
        
from qt
Ezzel pedig Endyl megoldása így nézne ki:

with recursive qt(szam, nap) as (
    select
    0, current_date

    union all

    select
    szam + 1, date_sub(nap, interval 1 day)

    from qt

    where szam < 6
)
select
qt.nap,
sum(m.mego <=> 'Jó') jo

from qt
left join matek m on qt.nap = date(m.ido)

where (id = 26 or id is null)

group by date(qt.nap)

order by qt.nap
Apró megjegyzések:
  • Endyl megoldása tegnaptól számol vissza, az enyém mától. De mindkettőn lehet állítani.
  • Vladimir Baranov dátum táblája nem elegáns, de hatékony. Főleg, mert az SQL lekérdezés nem bonyolódik el.
  • Ha „kézzel” generált dátum listát használsz, gondolj arra is, hogy nem volna jobb közvetlenül adatsorként generálni őket PHP-ból (vagy amit használsz):
    
    select
    qt.column_0,
    sum(m.mego <=> 'Jó') jo
    
    from (
        values
            row('2021-04-14'),
            row('2021-04-15'),
            row('2021-04-16'),
            row('2021-04-17'),
            row('2021-04-18'),
            row('2021-04-19'),
            row('2021-04-20')
    ) qt
    left join matek m on qt.column_0 = date(m.ido)
    
    where (id = 26 or id is null)
    
    group by date(qt.column_0)
    
    order by qt.column_0
    


Plusz egy tanács: where'$id' = id helyett inkább szokj rá az SQL paraméter használatára. where :id = id vagy where ? = id, attól függ mit használsz.
22

Köszönöm a segítséget.

misike · 2021. Ápr. 21. (Sze), 13.46
Ez milyen sql?
25

Ez milyen sql? Őőő… MySQL.

kuka · 2021. Ápr. 21. (Sze), 15.09
Ez milyen sql?

Őőő… MySQL. Bár attól tartok nem ezt kérdezhetted.
26

Szerintem de, mert ez bennem

mind1 valami név · 2021. Ápr. 21. (Sze), 16.11
Szerintem de, mert ez bennem is felmerült, csak kipróbáltam postgresql alatt és legalább részben ott is működik, szóval elkönyveltem, hogy nagyon le vagyok maradva. :)
28

Nekem nem fut le saját gépen.

misike · 2021. Ápr. 21. (Sze), 19.15
Nekem nem fut le saját gépen. A Neten ugyan nem próbáltam.
mysqlnd 5.0.11-dev verziót használok.
29

Bocs, pontosítok: MySQL 8.0

kuka · 2021. Ápr. 22. (Cs), 00.56
Bocs, pontosítok: MySQL 8.0 vagy újabb. Sajnos náluk a CTE támogatás elég későn, csak 2018-ban jelent meg.

Vagy ha esetleg MariaDB is akad kézügyben, az már a 2016-ban megjelent 10.2 óta tudja.

kipróbáltam postgresql alatt és legalább részben ott is működik

Ott 8.4 óta lehetséges, ami 2009-ben jelent meg.

Még a viszonylag egyszerű SQLite is már 2014-ben megkapta a támogatást a 3.8.3-as verzióval.

Oracle és MSSQL dokumentációk már nem is említik, annyira alapnak számít, hogy a kezdetek a feledés homályába vesztek.