Autor Zpráva
stepanka
Profil *
Ahoj,

uměl by mi někdo prosím poradit? Mám tabulku:

id_produkt  id_hodnota
1  23
1  24 
1  28
2  23 
2  25
2  31
3  18
3  24
3  32
4  23
4  24
4  28


A potřebuju vyhledat taková ID produktu, která se shodují ve všech hodnotách. Z příkladu by to byly produkty 1 a 4.
Pokud by někdo věděl, jak na to, budu moc vděčná.

Díky!
Jozin
Profil
Ahoj,

asi nerozumím tomu co chceš. 1. a 4. řádek se shodují jen v id_hodnota. Pokud hledáš duplicitu jak id_produkt tak id_hodnota, tak tu tam nikde nevidím.

Data jsou v databázi, což znamená, že přidáním primárního klíče se znemožní duplicita, což je možná to, čeho chceš docílit.

Pokud jsem mluvil o něčem naprosto jiném, tak se omlouvám, nějak jsem to nepochopil.

Jozin.
TomášK
Profil
Jozin:
Jde o id_produktu 1 a 4, kterým odpovídají stejné n-tice (23, 24, 28), nikoliv o záznamy na 1. a 4. řádku.

stepanka:
Kolik je těch záznamů, kolik je různých produktů a hodnot? Bez použití procedury mě napadá řešení s kvadratickou složitostí, ale jde to asi i lineárně. Které je vhodnější?
stepanka
Profil *
Jozin:
Ano, přesně jak píše TomášK

TomášK:
Produktů je 34926, hodnot 519. Ty hodnoty jsou parametry kontaktních čoček a já potřebuju vyhledat duplicitní záznamy (to jen abys byl v obraze).

Bez použití procedury mě napadá řešení s kvadratickou složitostí, ale jde to asi i lineárně.
A já si říkala, proč na ten dotaz nemůžu přijít... Jinými slovy - nemám tucha o čem je řeč. Možná tam bude taky problém, že ne všechny produkty mají stejný počet hodnot (některé jich mají víc, některé míň). Bylo by to moc složité?
Kajman_
Profil *
Asi to není zrovna nejčistější řešení, ale možná by šlo něco jako
select group_concat(t.id_produkt) produkty
from   (select id_produkt,
               count(distinct id_hodnota) pocet,
               sum(distinct id_hodnota) suma,
               group_concat(distinct id_hodnota order by id_hodnota) seznam
        from   tabulka
        group  by id_produkt) t
group  by t.pocet, t.suma, t.seznam
having count(*) > 1
TomášK
Profil
stepanka:
A já si říkala, proč na ten dotaz nemůžu přijít... Jinými slovy - nemám tucha o čem je řeč.
Řeč je o tom, jak dlouho to bude trvat. Algoritmus se složitostí lineární aneb O(n) znamená, že počet operací vykonaných algoritmem bude přímo úměrný počtu záznamů, tedy c*35 000. Kvadratická složitost aneb O(n^2) znamená, že počet operací bude úměrný c*35 000^2 = c*1 225 000 000 (opět krát nějaká konstanta). c je nějaká konstanta, závislá na konkrétní implementaci algoritmu, složitosti jednoho kroku. Kdybych ji odhadl třeba 100 a počet operací, které dokáže procesor vykonat za vteřinu na 1 000 000 000, bude algoritmus s lineární složitostí trvat zlomek vteřiny, algoritmus s kvadratickou složitostí minuty. Je dobré mít o tomhle aspoň základní představu, abys dokázala odhadnout, co ještě jde spočítat a co už ne.

Kajman:
To mi přišlo tak ošklivé, že jsem to raději nepsal :)

Tu je řešení, které by mělo fungovat, ale dost možná to jde i rychleji.
SELECT
    id_produkt1,
    id_produkt2
FROM 
    -- kanditáti na duplicitní produkty - mají stejný počet hodnot
    (
        SELECT
            produkty1.id_produkt AS id_produkt1,
            produkty2.id_produkt AS id_produkt2,
            produkty1.pocet
        FROM
            -- spočítáme počet hodnot pro každý produkt
            (
                SELECT 
                    id_produkt, 
                    COUNT(*) AS pocet
                FROM 
                    t
                GROUP BY id_produkt
            ) AS produkty1 
            -- ještě jednou totéž, protože nefunguje 'JOIN produkty1 AS produkty2'
            JOIN (
                SELECT 
                    id_produkt, 
                    COUNT(*) AS pocet
                FROM 
                    t
                GROUP BY id_produkt
            ) AS produkty2 ON produkty1.pocet = produkty2.pocet AND produkty1.id_produkt < produkty2.id_produkt
    ) kandidati

    -- Máme dvojice kandidátů. Pokud má dvojice shodné množiny hodnot, bude mít JOIN přes hodnotu stejný počet řádků
    -- jako mají kandidáti počet hodnot, jinak menší
    JOIN t AS t1 ON t1.id_produkt = kandidati.id_produkt1
    JOIN t AS t2 ON t2.id_produkt = kandidati.id_produkt2 AND t2.id_hodnota = t1.id_hodnota 
GROUP BY kandidati.pocet, t1.id_produkt, t2.id_produkt
HAVING COUNT(*) = pocet;
stepanka
Profil *
Hoši, vy jste blázni, takové výtvory by zasluhovaly medaili... Moc vám děkuju!

Kajman:
Ten Tvůj dotaz mi vrátí několik desítek záznamů typu [BLOB - 8B], [BLOB - 11B], atd. Možná je to nějaký standardní výstup, ale zatím jsem jaksi nepřišla na to, jak s tímhle výstupem naložit. Když zruším ten "group_concat", vyhodí mi to IDčka produktů, což byl výstup pro mě přijatelnější, ale zase jsem nepřišla na logiku, podle které mám k sobě spárovat ty stejné produkty (rozklikla jsem jich pár a každý byl jiný).

TomášK:
S tou složitostí tomu rozumím, děkuju za vysvětlení. Brali jsme to dva roky zpátky ve škole, akorát jsem to ještě nikdy neimplementovala do databází. Ohledně toho dotazu - ten zatím nemůžu posoudit. Když jsem ho spustila na serveru, skončilo to timeoutem po několika minutách. Když jsem ho spustila na lokále, kde mám nastaven běh skriptu na, podle dnešní zkušenosti, snad nekonečno, tak se točil a točil a až úplného zasekání kompu. Zítra to vyzkouším na silnějším stroji.
TomášK
Profil
stepanka:
Je na té tabulce index (id_produkt, id_hodnota)? Je-li to pomalé, pak bych udělal ručně (ať už procedurou v php nebo sql) ekvivalent toho, co napsal Kajman. Na tom řešení se mi nelíbí, že z toho group concat dělá řetězce. Vytáhl bych si ke každému produktu všechny hodnoty, ty uložil do seřazeného pole. Poté setřídil produkty podle hodnot (tj. porovnám nejmenší hodnoty, pokud jsou stejné, pak druhé nejmenší atd.). Pokud existují duplicitní produkty, budou v seřazeném poli vedle sebe, stačí tedy pole projít a porovnat sousední produkty, jestli mají stejné hodnoty nebo ne. Je možné, že to i s implementací bude rychlejší než doběhne ten SELECT :-)
Kajman_
Profil *
stepanka:
A co třeba převést ten blob na řetězec, když ho zvolený klient nezobrazí? Nebo zkusit jiného klienta.
Kajman_
Profil *
TomášK:
Seznam kandidátů by šel omezit použitím více agregačních funkcí, než jen count - (sum, min, max a možná budou vhodnější i jiné).
stepanka
Profil *
TomášK:
Tak Tvůj dotaz se mi bohužel nepovedlo nikde dokončit. Indexy tam byly a jsou. Ale to nevadí, nakonec jsem použila ten druhý. I tak Ti moc děkuju za ochotu a pomoc.

Kajman_:
Máš pravdu, v jiné databázi se dal ten BLOB převést na text, takže se mi zobrazily ID stejných produktů vedle sebe, což je to, co jsem chtěla dostat. Ještě jsem si ten výsledek v PHP vylepšila, zredukovala počet výsledků a funguje to skvěle. Mockrát Ti děkuju za pomoc.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0