Seçili bir alt sorgudan birden çok sütun alın


24
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)

Gördüğünüz gibi sadece başka bir sütun çıkarmak için aynı alt sorguyu tekrarlıyorum. Merak ediyorum, bunu yapmanın daha iyi bir yolu var mı?

id , her iki tabloda da birincil anahtardır. Bu yardımcı olabilir eğer product_special.priority benzersiz yapma konusunda hiçbir sorunum yok .

Yanıtlar:


11

Kombinasyonun product_special.id, product_special.prioritybenzersiz olduğunu varsayarak

 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)

5

alanları special_price.price ve date.date olarak döndürmeyi düşünmüyorsanız, neden alt sorgudaki isimleri takma ad vermiyorsunuz? Örneğin

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

Sorgu dilinizin bir FIRST () toplama işlevi var mı? Product_special ürününün PK'sini kimlik ve öncelik arasında bir bileşik haline getirip getirmeyeceğinden emin değil ve SİPARİŞ yan tümcesini değiştirGROUP BY id, psi.priority

ORDER BY yan tümcesini tamamen kaldırabilir ve kullanabilirsiniz. HAVING MIN(psi.priority)


2

SQL Server'dan "çapraz uygulama" mekanizmasının bunu çözeceğini, ancak PostgreSQL'de bulunmadığını unutmayın. Temel olarak, FROM yan tümcesinde tablo ifadeleri olarak adlandırılan işlevlere parametrelerin (geçerli tablo ifadesinin dışına sütunlara gönderme eğiliminde olan) nasıl aktarılacağına dair çözüm önerileriydi. Ancak, FROM yan tümcesinden SELECT yan tümcesine başka bir alt sorgu iç içe geçme veya eşyalar yerleştirmekten kaçınmak istediğiniz her türlü durum için faydalı olduğu ortaya çıktı. PostgreSQL bunu bir istisna yaparak gerçekleştirmeyi mümkün kılmıştır - ifade basit bir işlev çağrısıysa ancak gömülü bir SELECT ifadesini tam olarak konuşmuyorsa, bunun gibi parametreleri geçebilirsiniz. Yani

left join highestPriorityProductSpecial(p.id) on true

tamam ama değil

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

Fonksiyonun tanımı tam olarak bu olsa bile.

Yani, bu aslında kullanışlı bir çözümdür (en azından 9.1'de): fonksiyonun sınırını çizerek en yüksek öncelikli sıranızı çıkarmak için bir işlev yapın.

Ancak işlevler, sorgu planının içlerinde neler olup bittiğini göstermeyeceği dezavantajına sahiptir ve en iyisi olmasa bile, her zaman iç içe geçmiş bir döngü birleştirmeyi seçeceğine inanıyorum.


6
cross apply ise 9.3 ile başlayan Postgres olanağı (2013 yılında yayımlanan) ancak SQL standardına uyması ve standart kullanmayı tercih lateraloperatörü. İkinci sorgunuzdaleft joinleft join lateral
a_horse_with_no_name

2

Aşağıdaki SQL komutunu deneyin:

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

1
Lütfen cevabınıza daha fazla bilgi ekler misiniz
Ahmad Abuhasna

Söz konusu kod kullanılır LIMITve bir DBMS ile etiketlenmez (bu nedenle MySQL veya Postgres veya SQLite veya muhtemelen başka bir dbms olabilir). Cevaptaki kod kullanılır OUTER APPLYve TOPbu nedenle yalnızca sahip olmayan SQL Server'da (ve Sybase'de) çalışır LIMIT.
ypercubeᵀᴹ

Bu, sql sunucusu için yalnızca select deyimi içinde iç sorguyu kullanabileceğimiz diğer veritabanları için geçerlidir.
SANTOSH APPANA

Postgres'te yok OUTER APPLY, ama eşdeğeri olması gereken LATERAL var . Bunu kullanan bir örnek: stackoverflow.com/a/47926042/4850646
Lucas Basquerotto 12:18

2

Dezso'nun yanıtından esinlenerek /dba//a/222471/127433 PostgreSQL'de sorunu şu şekilde dizileri kullanarak çözüyorum :

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)

Kuşkusuz hala sadece bir sütun, ama kodumda iki değere kolayca erişebiliyorum. Umarım sizin için de işe yarar.


1

Bunu buraya son çare olarak koymak istiyorum, başka bir veya daha fazla cevabı desteklemeyen veritabanı motorunu kullanan herkes için ...

Gibi bir şey kullanabilirsiniz:

SELECT (col1 || col2) as col3 

(Ayırıcıyla veya col1 ve col2'yi belirli bir uzunluğa biçimlendirerek.) Ve daha sonra alt dizeleri kullanarak verilerinizi çizin.

Umarım birileri onu yararlı bulur.


0

Z / OS, burada kullanım için DB2 packve unpackişlevleri bir subselect birden çok sütun dönün.

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);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.