it-swarm-eu.dev

Získejte více sloupců z vybraného poddotazu

SELECT 
   *, 
   p.name AS name, 
   p.image, 
   p.price,
   ( 
       SELECT ps.price 
       FROM product_special ps 
       WHERE p.id = ps.id
         AND ps.date < NOW() 
       ORDER BY ps.priority ASC, LIMIT 1
   ) AS special_price,
   ( 
       SELECT ps.date 
       FROM product_special ps 
       WHERE p.id = ps.id
         AND ps.date < NOW() 
       ORDER BY ps.priority ASC, LIMIT 1
   ) AS date
FROM product p LEFT JOIN product_special ps ON (p.id = ps.id)

Jak vidíte, opakuji stejný poddotaz, jen abych dostal další sloupec. Zajímalo by mě, existuje lepší způsob, jak toho dosáhnout?

id je primární klíč v obou tabulkách. Nemám problém dělat product_special.priority jedinečný, pokud to může pomoci.

26
Sparctus

Předpokládaná kombinace product_special.id, product_special.priority je jedinečný

 SELECT p.*, special_price,special_date
 FROM product p
 LEFT JOIN 
 (
     SELECT ps.id, ps.price as special_price, ps.`date` as special_date
     FROM product_special ps
     INNER JOIN 
     (
       SELECT id, MIN(priority) as min_priority 
       FROM product_special
       GROUP BY id
     ) ps2 
     ON (ps2.id = ps.id)
 )a ON (a.id=p.id)
11
a1ex07

pokud nemáte v úmyslu vrátit pole jako special_price.price a date.date, proč ne alias jména uvnitř poddotazu? např.

SELECT p.*, p.name AS  name, p.image, p.price, ps.*
FROM product p
LEFT JOIN
   (SELECT
      psi.price as special_price, psi.date as my_date 
    FROM product_special psi
    WHERE 
      p.id = psi.id AND
      psi.date < NOW()
    ORDER BY psi.priority ASC, LIMIT 1
   ) AS ps ON
  p.id = ps.id

Má váš dotazovací jazyk agregovanou funkci FIRST ()? Nejste si jisti, zda byste mohli z PK produktu product_special udělat kompozit mezi id a prioritou (oba ASC řazení) a změnit klauzuli ORDER na GROUP BY id, psi.priority

mŮŽETE být schopen zcela odstranit klauzuli ORDER BY a použít HAVING MIN(psi.priority)

5
mpag

Všimněte si, že by to vyřešil mechanismus „křížového použití“ ze serveru SQL, ale v PostgreSQL není k dispozici. V zásadě to bylo jejich řešení, jak předávat parametry (které mají tendenci být odkazy na sloupce vně aktuálního výrazu tabulky) funkcím nazývaným jako tabulkové výrazy v klauzuli FROM. Ukázalo se však, že je užitečné pro všechny druhy situací, ve kterých se chcete vyhnout další úrovni vnořování poddotazů nebo přesunu věcí z klauzule FROM do klauzule SELECT. PostgreSQL to umožnilo tak, že udělalo výjimku - parametry můžete předat, pokud je výrazem jednoduché volání funkce, ale nikoli striktně řečeno vložený SELECT. Tak

left join highestPriorityProductSpecial(p.id) on true

je v pořádku, ale ne

left join (select * from product_special ps where ps.id = p.id order by priority desc limit 1) on true

i když definice funkce je přesně taková.

Takže to je ve skutečnosti šikovné řešení (alespoň v 9.1): vytvořte funkci, která extrahuje nejvyšší řádek priority provedením limitu uvnitř funkce.

Funkce však mají tu nevýhodu, že plán dotazů neukáže, co se v nich děje, a já věřím, že si vždy vybere připojení vnořené smyčky, i když to nemusí být nejlepší.

2
Paul Vaughan

Inspirován odpovědí dezso https://dba.stackexchange.com/a/222471/1274 Řeším problém v PostgreSQL pomocí polí, jako je tato:

SELECT 
   *, 
   p.name AS name, 
   p.image, 
   p.price,
   ( 
       SELECT ARRAY[ps.price, ps.date]
       FROM product_special ps 
       WHERE p.id = ps.id
         AND ps.date < NOW() 
       ORDER BY ps.priority ASC, LIMIT 1
   ) AS special_price_and_date
FROM product p LEFT JOIN product_special ps ON (p.id = ps.id)

Je pravda, že je to stále jen jeden sloupec, ale v mém kódu mám snadný přístup ke dvěma hodnotám. Doufám, že to funguje i pro vás.

2
tobi42

Vyzkoušejte následující příkaz SQL:

SELECT p.name,p.image,p.price,pss.price,pss.date
FROM Product p OUTER APPLY(SELECT TOP(1)* 
FROM ProductSpecial ps
WHERE p.Id = ps.Id ORDER BY ps.priority )as pss
2
SANTOSH APPANA

Chci to dát sem pro poslední možnost, pro každého, kdo používá databázový stroj, který nepodporuje jednu nebo více dalších odpovědí ...

Můžete použít něco jako:

SELECT (col1 || col2) as col3 

(S oddělovačem nebo formátováním col1 a col2 na specifickou délku.) A později nakreslete svá data pomocí pomocných řetězců.

Doufám, že to někdo považuje za užitečné.

2
H.A.H.

V produktu DB2 for z/OS použijte funkce pack a unpack pro vrácení více sloupců v dílčím výběru.

SELECT 
   *, 
   p.name AS name, 
   p.image, 
   p.price,
    unpack((select PACK (CCSID 1028,
               ps.price,
               ps.date)
         FROM product_special ps 
       WHERE p.id = ps.id
         AND ps.date < NOW() 
       ORDER BY ps.priority ASC, LIMIT 1)) .* AS (SPECIAL_PRICE double, DATE date)
FROM product p LEFT JOIN product_special ps ON (p.id = ps.id);
0
Keith C