อ้างถึงคอลัมน์ชื่อแทนใน WHERE Clause


166
SELECT logcount, logUserID, maxlogtm
   , DATEDIFF(day, maxlogtm, GETDATE()) AS daysdiff
FROM statslogsummary
WHERE daysdiff > 120

ฉันเข้าใจ

"ชื่อคอลัมน์ไม่ถูกต้อง daysdiff"

Maxlogtm เป็นฟิลด์ datetime มันเป็นสิ่งเล็กน้อยที่ทำให้ฉันบ้า


ไม่แน่ใจสำหรับ MySQL `daysdiff`แต่บางทีนามแฝงจะต้องห่อในเห็บ
Ash Burlaczenko

คำตอบ:


194
SELECT
   logcount, logUserID, maxlogtm,
   DATEDIFF(day, maxlogtm, GETDATE()) AS daysdiff
FROM statslogsummary
WHERE ( DATEDIFF(day, maxlogtm, GETDATE() > 120)

โดยปกติแล้วคุณไม่สามารถอ้างถึงสมนามฟิลด์ในWHEREประโยค (คิดว่าเป็นภาพSELECTรวมรวมถึงชื่อแทนถูกนำไปใช้หลังจากWHEREข้อ)

แต่ดังที่กล่าวไว้ในคำตอบอื่น ๆ คุณสามารถบังคับให้ SQL SELECTจัดการกับการจัดการก่อนส่วนWHEREคำสั่ง โดยปกติจะทำด้วยวงเล็บเพื่อบังคับลำดับการดำเนินการทางตรรกะหรือด้วย Common Table Expression (CTE):

วงเล็บ / subselect:

SELECT
   *
FROM
(
   SELECT
      logcount, logUserID, maxlogtm,
      DATEDIFF(day, maxlogtm, GETDATE()) AS daysdiff
   FROM statslogsummary   
) as innerTable
WHERE daysdiff > 120

หรือดูคำตอบของอดัมสำหรับรุ่น CTE ที่เหมือนกัน


16
สิ่งนี้เป็นไปไม่ได้โดยตรงเนื่องจากตามลำดับเหตุการณ์เกิดขึ้นก่อนที่ SELECT ซึ่งมักจะเป็นขั้นตอนสุดท้ายในห่วงโซ่การดำเนินการ ผู้อ้างอิง - stackoverflow.com/questions/356675/…
david blaine

afaik ถ้า alias ใน select เป็นแบบสอบถามย่อยที่สัมพันธ์กันซึ่งจะทำงานในขณะที่โซลูชัน CTE จะไม่ทำงาน
Răzvan Flavius ​​Panda

ตามที่ Pascal พูดถึงในคำตอบของเขาที่นี่stackoverflow.com/a/38822328/282887คุณสามารถใช้ HAVING clause ซึ่งดูเหมือนว่าจะทำงานได้เร็วกว่าเคียวรี่ย่อย
Bakhtiyor

@Bakhtiyor HAVINGคำตอบไม่ได้ผลในสภาพแวดล้อม SQL ส่วนใหญ่รวมถึง MS-SQL ที่คำถามนี้เกี่ยวกับ (ใน T-SQL HAVINGต้องการฟังก์ชันการรวม)
Jamie F

72

หากคุณต้องการใช้นามแฝงในWHEREข้อของคุณคุณต้องล้อมมันในตัวเลือกย่อยหรือCTE :

WITH LogDateDiff AS
(
   SELECT logcount, logUserID, maxlogtm
      , DATEDIFF(day, maxlogtm, GETDATE()) AS daysdiff
   FROM statslogsummary
)
SELECT logCount, logUserId, maxlogtm, daysdiff
FROM LogDateDiff
WHERE daysdiff > 120

2
คุณรู้หรือไม่ว่าการจัดงานแสดงสินค้านี้มีประสิทธิภาพอย่างชาญฉลาดหรือไม่? มีค่าใช้จ่ายพิเศษในการใช้ CTE หรือไม่?
James

5
CTE เป็นเพียงไวยากรณ์ที่สวยกว่าสำหรับคิวรีย่อยดังนั้นประสิทธิภาพจะคล้ายกับที่ จากประสบการณ์ของฉันความแตกต่างด้านประสิทธิภาพไม่ได้เป็นสิ่งที่เกี่ยวข้องกับฉันสำหรับการดำเนินการเช่นนี้ แต่ควรทดสอบอย่างง่ายในสภาพแวดล้อมของคุณเพื่อดูว่าตาราง / แบบสอบถามเฉพาะของคุณได้รับผลกระทบกับสิ่งนี้หรือไม่ สูตรเฉพาะในข้อที่ ฉันสงสัยว่าคุณจะไม่สังเกตเห็นความแตกต่าง
Adam Wenger

CTE นั้นดีมากจนกระทั่งคุณลองใช้มันเป็นแบบสอบถามย่อย ฉันต้องใช้วิธีสร้างเป็นมุมมองเพื่อซ่อนไว้ ฉันคิดว่านี่เป็นข้อผิดพลาดร้ายแรงของ SQL
symbiont

10

วิธีที่มีประสิทธิภาพที่สุดในการทำโดยไม่ต้องทำซ้ำรหัสของคุณคือการใช้HAVINGแทนที่จะเป็นWHERE

SELECT logcount, logUserID, maxlogtm
   , DATEDIFF(day, maxlogtm, GETDATE()) AS daysdiff
FROM statslogsummary
HAVING daysdiff > 120

1
ฉันคิดว่าการใช้HAVINGชื่อแทนนั้นไม่ได้มาตรฐาน (ใช้ได้กับ MySQL) โดยเฉพาะฉันคิดว่ามันใช้ไม่ได้กับ SQL Server
tokland

2
SQL Server:[S0001][207] Invalid column name 'daysdiff'
Vadzim

3
SQL Server:[S0001][8121] Column 'day' is invalid in the HAVING clause because it is not contained in either an aggregate function or the GROUP BY clause.
Vadzim

9

หากคุณไม่ต้องการแสดงรายการคอลัมน์ทั้งหมดของคุณใน CTE วิธีอื่นในการทำเช่นนี้ก็คือการใช้outer apply:

select
    s.logcount, s.logUserID, s.maxlogtm,
    a.daysdiff
from statslogsummary as s
    outer apply (select datediff(day, s.maxlogtm, getdate()) as daysdiff) as a
where a.daysdiff > 120

6

วิธีการเกี่ยวกับการใช้แบบสอบถามย่อย (นี้ทำงานให้ฉันใน Mysql)

SELECT * from (SELECT logcount, logUserID, maxlogtm
   , DATEDIFF(day, maxlogtm, GETDATE()) AS daysdiff
FROM statslogsummary) as 'your_alias'
WHERE daysdiff > 120

4

HAVING ทำงานใน MySQL ตามเอกสาร:

ส่วนคำสั่งHAVINGถูกเพิ่มไปยัง SQL เนื่องจากไม่สามารถใช้คำสำคัญ WHERE กับฟังก์ชันรวมได้


4

คุณสามารถอ้างถึงนามแฝงคอลัมน์ แต่คุณจำเป็นต้องกำหนดโดยใช้CROSS/OUTER APPLY:

SELECT s.logcount, s.logUserID, s.maxlogtm, c.daysdiff
FROM statslogsummary s
CROSS APPLY (SELECT DATEDIFF(day, s.maxlogtm, GETDATE()) AS daysdiff) c
WHERE c.daysdiff > 120;

การสาธิต DBFiddle

ข้อดี:

  • คำจำกัดความนิพจน์เดียว (ง่ายต่อการดูแล / ไม่จำเป็นต้องคัดลอก - วาง)
  • ไม่จำเป็นต้องห่อแบบสอบถามทั้งหมดด้วย CTE / แบบสอบถามนอก
  • ความเป็นไปได้ที่จะอ้างอิงถึง WHERE/GROUP BY/ORDER BY
  • ประสิทธิภาพที่ดีขึ้นเป็นไปได้ (การประมวลผลครั้งเดียว)

1
มันคุ้มค่าที่จะกล่าวถึงว่ามันจะทำงานเฉพาะใน SQL Server
มาร์ติน Zinovsky

1
@MartinZinovsky คำถามถูกติดแท็กด้วยsql-serverและt-sql:)
Lukasz Szozda

0

มาที่นี่กำลังมองหาบางอย่างที่คล้ายกัน แต่มีกรณีเมื่อและจบลงด้วยการใช้ที่เช่นนี้: WHERE (CASE WHEN COLUMN1=COLUMN2 THEN '1' ELSE '0' END) = 0บางทีคุณสามารถใช้DATEDIFFในWHEREโดยตรง สิ่งที่ต้องการ:

SELECT logcount, logUserID, maxlogtm
FROM statslogsummary
WHERE (DATEDIFF(day, maxlogtm, GETDATE())) > 120
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.