SQL select

Tuxik

  • *****
  • 1 473
    • Zobrazit profil
    • E-mail
SQL select
« kdy: 05. 07. 2015, 07:46:15 »
Ahoj, potreboval bych vztvorit SQL dotaz (jedna se FireBird, ale muze byt i pro MySQL, kdyztak prevedu, kdzby to neslo jinak).

Mam tabulku, ve ktere jsou k urcitemu ID pritrazeny vlastnosti. Vzdy jedno ID, jedna vlastnost na radku. ID se muze opakovat a muze mit i vic vlastnosti. Potrebuji vybrat pouze ID, ktere ma vic konkretnich vlastnosti. Pokusim se vysvetlit tabulkou.
Kód: [Vybrat]
+---+----------+
| ID | Vlastnost |
+---+----------+
|  1 |            A |
|  2 |            A |
|  2 |            B |
|  3 |            A |
|  3 |            C |
+---+----------+

Potrebuji  vybrat jen ID, ktere ma prirazenu napr. vlastnost A i B (v tomto pripade ID 2), pripadne rozsirit na noznost vybrat kazde ID, ktere ma A a k tomu B nebo C (v tomto pripade ID 2 a 3).

Existuje nejaka jednoducha moznost, nebo to budu muset postupne prochazet? Bylo by to idealni v ramci jednoho dotazu, aby podminku mohl zadat uzivatel, klidne v nejakem zapisu neco jako "SELECT DISTINCT ID from TBL WHERE Vlastnost=A and (Vlastnost=B OR Vlastnost=C)", respektive jenom podminkove casti zapisu, ale aby to slo idealne jednim dotazem a nemuselo se resit nejake slozite parsovani dotazu a jeho provadeni.

Dekuji za rady


Nemo7

Re:SQL select
« Odpověď #1 kdy: 05. 07. 2015, 09:33:06 »
GROUP BY ID, Vlastnost HAVING COUNT(Vlastnost)>=2 by nešlo?

e3k

Re:SQL select
« Odpověď #2 kdy: 05. 07. 2015, 11:13:53 »
ten tvoj:

SELECT DISTINCT ID from TBL WHERE Vlastnost=A and (Vlastnost=B OR Vlastnost=C)

je na tento ucel presne to co hladas.

Nemo7

Re:SQL select
« Odpověď #3 kdy: 05. 07. 2015, 11:43:04 »
ten tvoj:

SELECT DISTINCT ID from TBL WHERE Vlastnost=A and (Vlastnost=B OR Vlastnost=C)

je na tento ucel presne to co hladas.
Co když je vlastností víc než 3? Třeba 10?

whata

Re:SQL select
« Odpověď #4 kdy: 05. 07. 2015, 12:25:16 »
SELECT id FROM table GROUP BY id HAVING COUNT(vlastnost) >= 2;


e3k

Re:SQL select
« Odpověď #5 kdy: 05. 07. 2015, 13:24:45 »
SELECT id FROM table GROUP BY id HAVING COUNT(vlastnost) >= 2;
tak ich doplnis do podmienky?

Tuxik

  • *****
  • 1 473
    • Zobrazit profil
    • E-mail
Re:SQL select
« Odpověď #6 kdy: 05. 07. 2015, 14:33:59 »
Upozornuju, nasledujici reseni je pro FireBird (zkouseno na verzi 2.5)!!! Pro MySLQ je to podobny, ale misto LIST se pouziva GROUP_CONCAT a mozna jeste nejake drobne odlisnosti.
Uz jsem to vyresil, vytvoril jsem si vlastni pohled

Kód: [Vybrat]
create view MujPohled (ID, Vlastnosti) as select distinct ID, LIST('*' || Vlastnost || '*','') from Tabulka group by ID;
coz mi vytvori radky v MujPohled neco jako
Kód: [Vybrat]
ID    Vlastnosti
1    *A*
2    *A**B*
3    *A**C*
takze kazdou vlastnost mam ohranicenou z obou stran * a vyhledavam v nich pomoci napr

Kód: [Vybrat]
select ID from MujPohled where Vlastnosti like '*A*' and Vlastnosti like '*B*';coz mi najde vsechny ID obsahujici A i B a logika WHERE se da kombinovat neomezene, coz se mi hodi, protoze hledani generuju z PHP pomoci pravidel vytvorenych uzivatelem pres par tlacitek - '(' ')' 'AND' 'OR' 'pridat vlastnost'.

Sice se mi to zda porad nejaky prekombinovany a mozna bude existovat jednodussi metoda, ale takhle je to na tech par tisic radku co resim i docela rychly a hlavne to skladani podminek funguje bezvadne.

Re:SQL select
« Odpověď #7 kdy: 05. 07. 2015, 17:24:08 »
Sice se mi to zda porad nejaky prekombinovany a mozna bude existovat jednodussi metoda, ale takhle je to na tech par tisic radku co resim i docela rychly a hlavne to skladani podminek funguje bezvadne.
Ono nejde o to, ze to je překombinované, ale na větších datech to by to bylo asi i dost pomalé - je tam jednak skládání stringu, a potom vícenásobný LIKE. Pro pár tisíc řádek to nepoznáte, ale pro víc než desítky tisíc to může být dost špatné - nicméně dobré řešení asi neexistuje - způsob jaký používáte se označuje jako EAV a je to známý antipattern - taky proto se Vám s tím špatně dělá.

Obvyklé řešení je založené na vícenásobném selfjoinu, které by mělo být docela rychlé pokud podmínkám bude odpovídat tak do 3% řádků. Potom už asi může být rychlejší scan s HAVING.

Tuxik

  • *****
  • 1 473
    • Zobrazit profil
    • E-mail
Re:SQL select
« Odpověď #8 kdy: 07. 07. 2015, 10:19:36 »
Obvyklé řešení je založené na vícenásobném selfjoinu, které by mělo být docela rychlé pokud podmínkám bude odpovídat tak do 3% řádků. Potom už asi může být rychlejší scan s HAVING.

Jedná se o synchronizaci dat mezi databází dodavatele a e-shopem, která probíhá max 1x denně a jedná se o pár tisíc položek (z nichž se dál zpracovává jen pár set) Trvá to v řádu vteřin a nějaký výrazný skokový nárust objemu dat se nedá očekávat, takže zatím je to v pohodě.

Ale děkuji, aspoň jsem o něco chytřejší. Většinou pracuju s SQL jen v rámci vlastních projektů a datový modely si vytvářím tak, aby to bylo co nejpohodlnější a nejrychlejší na používání. Zpracování cizích databází (a ještě doprasených, většina dat nesmyslně rozházená do desítek malých tabulek s hromadou vazeb mezi nima, dotaz pro získání 10ti sloupců znamená 7 joinů) není zrovna můj koníček :-D

Tuxik

  • *****
  • 1 473
    • Zobrazit profil
    • E-mail
Re:SQL select
« Odpověď #9 kdy: 07. 07. 2015, 10:23:15 »
ten tvoj:

SELECT DISTINCT ID from TBL WHERE Vlastnost=A and (Vlastnost=B OR Vlastnost=C)

je na tento ucel presne to co hladas.

To je na nic, tabulka obsahuje páry "jedno ID <-> jedna vlastnost" , takže těžko použiju jakejkoliv výraz obsahující "AND", protože mi nemůže dát nikdy žádný výsledek.

Kolemjdoucí

Re:SQL select
« Odpověď #10 kdy: 07. 07. 2015, 10:59:48 »
Kód: [Vybrat]
+---+----------+
| ID | Vlastnost |
+---+----------+
|  1 |            A |
|  2 |            A |
|  2 |            B |
|  3 |            A |
|  3 |            C |
+---+----------+

Potrebuji  vybrat jen ID, ktere ma prirazenu napr. vlastnost A i B (v tomto pripade ID 2)

select table.id
from table
inner join table as table2 on table2.id=table.id and table2.vlastnost='B'
where table.vlastnost='A'
group by table.id
order by table.id

pripadne rozsirit na noznost vybrat kazde ID, ktere ma A a k tomu B nebo C (v tomto pripade ID 2 a 3).

select table.id
from table
inner join table as table2 on table2.id=table.id and (table2.vlastnost='B' or table2.vlastnost='C')
where table.vlastnost='A'
group by table.id
order by table.id

Většinou pracuju s SQL

S SQL dosud nepracuješ, jinak by pro tebe řešení výše uvedených problémů bylo denním chlebem.

Tuxik

  • *****
  • 1 473
    • Zobrazit profil
    • E-mail
Re:SQL select
« Odpověď #11 kdy: 07. 07. 2015, 11:20:06 »
Asi jsem dostatečně nezdůraznil, že uvedené možnosti byly pouze příklady, a potřebuji obecnější postup. Jde o to, aby si podmínku vytvořil v jednoduchým klikátku uživatel, který má k dispozici tlačítka "přidat vlastnost" "AND" "OR" "(" a ")" - mohl si naklikat cokoliv, třeba "(A and (B or C) and (D or E)) or G" - prostě cokoliv. Takhle naklikaný výraz potom jednoduše sparsuju PHPčkem do query, který použiju na to view, který jsem si vytvořil.

A ano, uznávám, s SQL nepracuju, spíš ho občas používám.

Jinak mám to sice vyřešený, ale jestli někdo přijde s nějakým elegantnějším řešením, tak ho určitě uvítám :)

Re:SQL select
« Odpověď #12 kdy: 07. 07. 2015, 11:34:14 »
Asi jsem dostatečně nezdůraznil, že uvedené možnosti byly pouze příklady, a potřebuji obecnější postup. Jde o to, aby si podmínku vytvořil v jednoduchým klikátku uživatel, který má k dispozici tlačítka "přidat vlastnost" "AND" "OR" "(" a ")" - mohl si naklikat cokoliv, třeba "(A and (B or C) and (D or E)) or G" - prostě cokoliv. Takhle naklikaný výraz potom jednoduše sparsuju PHPčkem do query, který použiju na to view, který jsem si vytvořil.

A ano, uznávám, s SQL nepracuju, spíš ho občas používám.

Jinak mám to sice vyřešený, ale jestli někdo přijde s nějakým elegantnějším řešením, tak ho určitě uvítám :)

Elegantní řešení na relační databázi neexistuje - z principu - to, co děláte prostě relační databáze nedělají. Můžete zkusit nerelační databázi - CouchDB, MongoDB, ElasticSearch - a tohle tam bude triviální - případně v Postgresu použít uložení do HStoru a dotazovat se nad HStorem (což je tak v podstatě už nerelační uložení dat).

Kolemjdoucí

Re:SQL select
« Odpověď #13 kdy: 07. 07. 2015, 11:35:53 »
Obecné elegantní řešení na takové obecné dotazování není.

Pomůže při importu uložit výsledek tohoto dotazu do speciální tabulky, řádně oindexovat a dotazy dělat tam.

select coalesce(table.id, table2.id, table3.id) as id, table.vlastnost as vlastnost_a, table2.vlastnost as vlastnost_b, table3.vlastnost as vlastnost_c
full outer join table as table2 on table2.id=table.id and table2.vlastnost='B'
full outer join table as table3 on table3.id=table.id and table3.vlastnost='C'
where table.vlastnost='A'

Re:SQL select
« Odpověď #14 kdy: 07. 07. 2015, 11:46:07 »
...
nicméně dobré řešení asi neexistuje - způsob jaký používáte se označuje jako EAV a je to známý antipattern - taky proto se Vám s tím špatně dělá.
...

Dlouho jsem s DB nic pořádného nedělal, ale zajímá mne to:
Pavle, co je v tomto případě ten antipattern?
Struktura té tabulky?
A pokud ano, jak by se to mělo řešit správně (mne teď v těch hicech nic nenapadá + viz výše), stačí třeba jen nějaký link na něco k přečtení ...