postgresql ส่งคืน 0 ถ้าค่าที่ส่งคืนเป็น null


106

ฉันมีข้อความค้นหาที่ส่งกลับค่าเฉลี่ย (ราคา)

  select avg(price)
  from(
      select *, cume_dist() OVER (ORDER BY price desc) from web_price_scan
      where listing_Type='AARM'
        and u_kbalikepartnumbers_id = 1000307
        and (EXTRACT(Day FROM (Now()-dateEnded)))*24 < 48
        and price>( select avg(price)* 0.50
                    from(select *, cume_dist() OVER (ORDER BY price desc)
                         from web_price_scan
                         where listing_Type='AARM'
                           and u_kbalikepartnumbers_id = 1000307
                           and (EXTRACT(Day FROM (Now()-dateEnded)))*24 < 48
                        )g
                   where cume_dist < 0.50
                 )
        and price<( select avg(price)*2
                    from( select *, cume_dist() OVER (ORDER BY price desc)
                          from web_price_scan
                          where listing_Type='AARM'
                            and u_kbalikepartnumbers_id = 1000307
                            and (EXTRACT(Day FROM (Now()-dateEnded)))*24 < 48
                        )d
                    where cume_dist < 0.50)
     )s

  having count(*) > 5

จะทำให้มันกลับมาเป็น 0 ได้อย่างไรหากไม่มีค่า


1
คุณแน่ใจหรือไม่ว่าแบบสอบถามของคุณมีรูปแบบที่ดี?
Luc M

2
@LucM: ไม่สามารถเป็นแบบสอบถามที่มีรูปแบบสมบูรณ์ ("having" clause without a "group by" clause.)
Mike Sherrill 'Cat Recall'

ทุกอย่างทำงานได้ดียกเว้นว่าบางครั้งเมื่อไม่ปฏิบัติตามกฎก็จะไม่ส่งคืนอะไรเลย นอกจากนี้ฉันจะรวบรวมโดยเฉลี่ยได้อย่างไรฉันไม่คิดว่ามันจะเป็นไปได้ || ประเด็นคืออะไร? การเลือกหลายรายการเป็นการเลือกfrom web_price_scanแยกกัน ไม่แน่ใจว่ามีปัญหาอะไรที่นี่?
Andrew

เป็นเรื่องปกติที่จะใช้havingอนุประโยคโดยไม่มีgroup by(ซึ่งมีค่าเริ่มต้นเป็นกลุ่มเดียว) ทำหน้าที่เป็นwhereประโยคเกี่ยวกับผลลัพธ์รวม ในกรณีนี้จะส่งคืนแถวก็ต่อเมื่อมีการส่งคืนมากกว่า 5 แถวโดยแบบสอบถามย่อยระดับที่ 1
bruceskyaus

คำตอบ:


186

ใช้ประสานกัน

COALESCE(value [, ...])
The COALESCE function returns the first of its arguments that is not null.  
Null is returned only if all arguments are null. It is often
used to substitute a default value for null values when data is
retrieved for display.

แก้ไข

นี่คือตัวอย่างของCOALESCEคำถามของคุณ:

SELECT AVG( price )
FROM(
      SELECT *, cume_dist() OVER ( ORDER BY price DESC ) FROM web_price_scan
      WHERE listing_Type = 'AARM'
        AND u_kbalikepartnumbers_id = 1000307
        AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
        AND COALESCE( price, 0 ) > ( SELECT AVG( COALESCE( price, 0 ) )* 0.50
                                     FROM ( SELECT *, cume_dist() OVER ( ORDER BY price DESC )
                                           FROM web_price_scan
                                           WHERE listing_Type='AARM'
                                             AND u_kbalikepartnumbers_id = 1000307
                                             AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
                                         ) g
                                    WHERE cume_dist < 0.50
                                  )
        AND COALESCE( price, 0 ) < ( SELECT AVG( COALESCE( price, 0 ) ) *2
                                     FROM( SELECT *, cume_dist() OVER ( ORDER BY price desc )
                                           FROM web_price_scan
                                           WHERE listing_Type='AARM'
                                             AND u_kbalikepartnumbers_id = 1000307
                                             AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
                                         ) d
                                     WHERE cume_dist < 0.50)
     )s
HAVING COUNT(*) > 5

COALESCEไม่ควรใช้IMHO AVGเนื่องจากมีการปรับเปลี่ยนค่า NULLหมายถึงไม่รู้จักและไม่มีอะไรอื่น SUMมันไม่ได้เหมือนการใช้งานใน ในตัวอย่างนี้หากเราแทนที่AVGด้วยSUMผลลัพธ์จะไม่ผิดเพี้ยน การเพิ่ม 0 เข้าไปในผลรวมไม่ได้ทำร้ายใคร แต่การคำนวณค่าเฉลี่ยด้วย 0 สำหรับค่าที่ไม่รู้จักคุณจะไม่ได้รับค่าเฉลี่ยที่แท้จริง

ในกรณีนั้นฉันจะเพิ่มprice IS NOT NULLในWHEREประโยคเพื่อหลีกเลี่ยงค่าที่ไม่รู้จักเหล่านี้


1
@ แอนดรูฉันพยายามให้ตัวอย่างคุณโดยใช้คำถามของคุณ แต่ฉันหลงทาง ฉันสงสัยว่าแบบสอบถามนี้ใช้งานได้จริง from web_price_scan...ดูเหมือนซ้ำแล้วซ้ำเล่า ...
Luc M

สำหรับผู้ที่สงสัยว่าNULLIF(v1, v2)ไม่สวยมากตรงข้ามของCOALESCEในการที่จะส่งกลับNULLถ้าเท่ากับv1 v2
sm

25

(คำตอบนี้ถูกเพิ่มเพื่อให้ตัวอย่างสั้นและกว้างขึ้นสำหรับคำถาม - โดยไม่รวมรายละเอียดเฉพาะกรณีทั้งหมดในคำถามเดิม)


มี "ปัญหา" สองประการที่แตกต่างกันที่นี่ประการแรกคือถ้าตารางหรือแบบสอบถามย่อยไม่มีแถวที่สองคือถ้ามีค่า NULL ในแบบสอบถาม

สำหรับทุกเวอร์ชันที่ฉันทดสอบ postgres และ mysql จะละเว้นค่า NULL ทั้งหมดเมื่อทำการหาค่าเฉลี่ยและจะส่งคืนค่า NULL หากไม่มีอะไรให้เฉลี่ย โดยทั่วไปแล้วสิ่งนี้สมเหตุสมผลเนื่องจาก NULL ถือว่าเป็น "ไม่ทราบ" หากคุณต้องการลบล้างสิ่งนี้คุณสามารถใช้ coalesce (ตามที่ Luc M แนะนำ)

$ create table foo (bar int);
CREATE TABLE

$ select avg(bar) from foo;
 avg 
-----

(1 row)

$ select coalesce(avg(bar), 0) from foo;
 coalesce 
----------
        0
(1 row)

$ insert into foo values (3);
INSERT 0 1
$ insert into foo values (9);
INSERT 0 1
$ insert into foo values (NULL);
INSERT 0 1
$ select coalesce(avg(bar), 0) from foo;
      coalesce      
--------------------
 6.0000000000000000
(1 row)

แน่นอน "จาก foo" สามารถแทนที่ด้วย "from (... ตรรกะที่ซับซ้อนใด ๆ ที่นี่ ... ) เป็น foo"

ตอนนี้แถว NULL ในตารางควรนับเป็น 0 หรือไม่? จากนั้นจะต้องใช้การรวมกันภายในการโทรเฉลี่ย

$ select coalesce(avg(coalesce(bar, 0)), 0) from foo;
      coalesce      
--------------------
 4.0000000000000000
(1 row)

3

ฉันคิดได้ 2 วิธีในการบรรลุสิ่งนี้:

  • IFNULL ():

    ฟังก์ชัน IFNULL () จะส่งคืนค่าที่ระบุหากนิพจน์เป็น NULL ถ้านิพจน์ไม่ใช่ NULL ฟังก์ชันนี้จะส่งคืนนิพจน์

ไวยากรณ์:

IFNULL(expression, alt_value)

ตัวอย่างของ IFNULL () พร้อมข้อความค้นหาของคุณ:

SELECT AVG( price )
FROM(
      SELECT *, cume_dist() OVER ( ORDER BY price DESC ) FROM web_price_scan
      WHERE listing_Type = 'AARM'
        AND u_kbalikepartnumbers_id = 1000307
        AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
        AND IFNULL( price, 0 ) > ( SELECT AVG( IFNULL( price, 0 ) )* 0.50
                                     FROM ( SELECT *, cume_dist() OVER ( ORDER BY price DESC )
                                           FROM web_price_scan
                                           WHERE listing_Type='AARM'
                                             AND u_kbalikepartnumbers_id = 1000307
                                             AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
                                         ) g
                                    WHERE cume_dist < 0.50
                                  )
        AND IFNULL( price, 0 ) < ( SELECT AVG( IFNULL( price, 0 ) ) *2
                                     FROM( SELECT *, cume_dist() OVER ( ORDER BY price desc )
                                           FROM web_price_scan
                                           WHERE listing_Type='AARM'
                                             AND u_kbalikepartnumbers_id = 1000307
                                             AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
                                         ) d
                                     WHERE cume_dist < 0.50)
     )s
HAVING COUNT(*) > 5
  • โคลีสซี ()

    ฟังก์ชัน COALESCE () ส่งคืนค่าที่ไม่ใช่ค่าว่างค่าแรกในรายการ

ไวยากรณ์:

COALESCE(val1, val2, ...., val_n)

ตัวอย่าง COALESCE () พร้อมกับคำถามของคุณ:

SELECT AVG( price )
FROM(
      SELECT *, cume_dist() OVER ( ORDER BY price DESC ) FROM web_price_scan
      WHERE listing_Type = 'AARM'
        AND u_kbalikepartnumbers_id = 1000307
        AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
        AND COALESCE( price, 0 ) > ( SELECT AVG( COALESCE( price, 0 ) )* 0.50
                                     FROM ( SELECT *, cume_dist() OVER ( ORDER BY price DESC )
                                           FROM web_price_scan
                                           WHERE listing_Type='AARM'
                                             AND u_kbalikepartnumbers_id = 1000307
                                             AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
                                         ) g
                                    WHERE cume_dist < 0.50
                                  )
        AND COALESCE( price, 0 ) < ( SELECT AVG( COALESCE( price, 0 ) ) *2
                                     FROM( SELECT *, cume_dist() OVER ( ORDER BY price desc )
                                           FROM web_price_scan
                                           WHERE listing_Type='AARM'
                                             AND u_kbalikepartnumbers_id = 1000307
                                             AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
                                         ) d
                                     WHERE cume_dist < 0.50)
     )s
HAVING COUNT(*) > 5

2
IFNULL () ไม่ใช่ฟังก์ชันใน Postgres สิ่งนี้อาจใช้ได้ในฐานข้อมูลอื่น แต่คำถามนี้เกี่ยวกับ Postgres โดยเฉพาะ
Jon Wilson
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.