SQL - ใช้นามแฝงใน Group By


143

แค่อยากรู้เกี่ยวกับไวยากรณ์ SQL ดังนั้นถ้าฉันมี

SELECT 
 itemName as ItemName,
 substring(itemName, 1,1) as FirstLetter,
 Count(itemName)
FROM table1
GROUP BY itemName, FirstLetter

สิ่งนี้จะไม่ถูกต้องเพราะ

GROUP BY itemName, FirstLetter 

ควรจะเป็น

GROUP BY itemName, substring(itemName, 1,1)

แต่ทำไมเราไม่สามารถใช้อดีตเพื่อความสะดวกได้?


13
ที่ได้รับอนุญาตใน Postgresql
Michael Buen

7
MySQL อนุญาตให้ใช้ด้วย
Kip

1
คุณกำลังพูดถึง rdbms ใด
Shiwangini

คำตอบ:


292

SQL ถูกนำมาใช้ราวกับว่าแบบสอบถามถูกดำเนินการตามลำดับต่อไปนี้:

  1. จากประโยค
  2. ประโยคที่
  3. จัดกลุ่มตามข้อ
  4. มีข้อ
  5. เลือกข้อ
  6. เรียงตามคำสั่ง

สำหรับระบบฐานข้อมูลเชิงสัมพันธ์ส่วนใหญ่คำสั่งนี้จะอธิบายว่าชื่อใด (คอลัมน์หรือชื่อแทน) นั้นถูกต้องเพราะจะต้องมีการแนะนำในขั้นตอนก่อนหน้า

ดังนั้นใน Oracle และ SQL Server คุณไม่สามารถใช้คำใน GROUP BY clause ที่คุณกำหนดใน SELECT clause ได้เนื่องจาก GROUP BY นั้นจะถูกดำเนินการก่อนที่จะเลือก SELECT clause

มีข้อยกเว้นคือ: MySQL และ Postgres ดูเหมือนจะมีความฉลาดเพิ่มเติมที่อนุญาต


3
ฉันชอบคำอธิบายนี้ แม้ว่าฉันจะไม่สามารถคาดเดาได้ว่ามันยากแค่ไหนที่จะเพิ่มลงในเครื่องยนต์เป็นน้ำตาลทราย
Haoest

11
มีความคิดใดที่ว่า DB นั้นฉลาดพอที่จะรับรู้ว่านิพจน์เดียวกันนั้นอยู่ในคำสั่ง SELECT และ GROUP BY โดยไม่ต้องทำการประเมินนิพจน์อีกครั้ง? เช่นถ้ามีGROUP BY substring(itemName, 1,1)ฐานข้อมูลฉลาดพอที่จะไม่ใช้ประสิทธิภาพของการคำนวณสตริงย่อยในส่วนคำสั่ง SELECT หรือไม่
กี

10
ในส่วนคำสั่ง SELECT ของแบบสอบถามที่มีการจัดกลุ่มคุณจะสามารถเข้าถึงนิพจน์ GROUP BY และค่ารวม ดังนั้นจึงไม่เกี่ยวกับความฉลาด มันจะต้องมีการดำเนินการเพื่อให้การจัดกลุ่มทำงาน (และเป็นที่ต้องการโดยมาตรฐาน SQL) แต่ในกรณีที่น่ารำคาญมากขึ้น (เช่นการแสดงออกที่เหมือนกันใน WHERE และ SELECT clause) ระบบฐานข้อมูลที่ล้ำสมัยจะคำนวณเพียงครั้งเดียวเท่านั้น การเพิ่มประสิทธิภาพนี้เรียกว่าร่วมกันกำจัดย่อยแสดงออก
Codo

6
คำสั่งดำเนินการเกี่ยวข้องกับคำถามอย่างไร ไม่เหมือนกับผู้ถามที่พยายาม GROUP BY ใน COUNT () ในความเป็นจริงแบบสอบถามตามที่ถามทำงานได้ดีใน MySQL และมีแนวโน้มว่า PostgreSQL ตามที่ระบุไว้ในความคิดเห็น

1
สำหรับ mysql sql_modeไม่รวมONLY_FULL_GROUP_BYใน bitmask ตัวเพิ่มประสิทธิภาพมีโอกาสที่จะให้ผลลัพธ์ที่ดีกว่าด้วยการใช้นามแฝงที่หลากหลาย / แตกต่างกันในHAVINGข้อ
Drew

28

คุณสามารถใช้คิวรีย่อยได้ตลอดเวลาเพื่อให้คุณสามารถใช้นามแฝงได้ แน่นอนตรวจสอบประสิทธิภาพ (เป็นไปได้ที่เซิร์ฟเวอร์ db จะรันทั้งสองอย่างเดียวกัน แต่ไม่เคยเจ็บที่จะยืนยัน):

SELECT ItemName, FirstLetter, COUNT(ItemName)
FROM (
    SELECT ItemName, SUBSTRING(ItemName, 1, 1) AS FirstLetter
    FROM table1
    ) ItemNames
GROUP BY ItemName, FirstLetter

2
ควรหลีกเลี่ยงแบบสอบถามย่อยที่อาจเกิดขึ้นเนื่องจากประสิทธิภาพการทำงานไม่ดี การใช้สำเนาของฟังก์ชั่นนั้นดีกว่ามากเพราะมันถูกตรวจพบโดยเครื่องมือเพิ่มประสิทธิภาพฐานข้อมูลและทำได้เพียงครั้งเดียว
Roland

1
@Roland แต่ไม่มีความแตกต่างในแผนการดำเนินการในกรณีนั้น มีการพิจารณาเรื่องอื่น ๆ หรือไม่?
Guido Mocha

@Roland, แบบสอบถามย่อยที่สัมพันธ์กันหรือไวยากรณ์อื่น ๆ ที่นำไปสู่การวนซ้ำหรือพฤติกรรมแบบแถวต่อแถวควรหลีกเลี่ยงและมีข้อ จำกัด ว่าคุณควรไปลึกเพียงใดกับแบบสอบถามย่อยที่ซ้อนกัน แต่โดยทั่วไปแล้วไม่เป็นความจริงเลย เพื่อประสิทธิภาพที่ไม่ดี ในกรณีนี้ตามที่ Chris ได้กล่าวไว้คุณสามารถตรวจสอบแผนการดำเนินการ (แผนแบบสอบถาม AKA อธิบายแผน) เปรียบเทียบทั้งแบบมีและไม่มีข้อความค้นหาย่อยและดูว่ามีความแตกต่างหรือไม่ ค่อนข้างมากทุกโปรแกรมฐานข้อมูลจะเขียนแบบสอบถามของคุณอีกครั้งดังนั้นคุณจึงไม่สามารถควบคุมสิ่งที่ถูกดำเนินการได้ทั้งหมด นั่นคือจุดของการประกาศไวยากรณ์
Davos

16

อย่างน้อยใน PostgreSQL คุณสามารถใช้หมายเลขคอลัมน์ใน resultset ใน GROUP BY clause ของคุณ:

SELECT 
 itemName as ItemName,
 substring(itemName, 1,1) as FirstLetter,
 Count(itemName)
FROM table1
GROUP BY 1, 2

แน่นอนว่าสิ่งนี้เริ่มเป็นปัญหาหากคุณทำสิ่งนี้แบบโต้ตอบและคุณแก้ไขแบบสอบถามเพื่อเปลี่ยนจำนวนหรือลำดับของคอลัมน์ในผลลัพธ์ แต่ยังคง.


GROUP BY FirstLetterได้รับอนุญาตใน Postgresql หากต้องการปัญญาลองเรียกใช้สิ่งนี้ใน Postgresql: เลือก substring (table_name, 1,2) เป็น tname จากกลุ่ม information_schema.tables โดย tname
Michael Buen

1
@MichaelBuen ดูเหมือนว่าอาจมีปัญหากับฉัน จากการทดสอบอย่างรวดเร็วดูเหมือนว่ามีนามแฝงและคอลัมน์ตารางฐานที่มีชื่อเดียวกันหลังได้รับความสำคัญ? SQL ซอ ดังนั้นหากการพึ่งพากลุ่มนี้ด้วยนามแฝงการเปลี่ยนแปลงคีมาในภายหลังอาจทำให้ข้อความค้นหาของคุณเงียบและเปลี่ยนซีแมนติกส์ได้
Martin Smith

@MartinSmith รู้เพียงว่าตอนนี้เป็น gotcha จะไม่ใช้สิ่งนั้นขอบคุณ เนื่องจาก PostgreSQL อนุญาตให้ทางลัดนั้นพวกเขาควรให้ความสำคัญกับนามแฝงมิฉะนั้นพวกเขาไม่ควรอนุญาตทางลัดนั้นเลย
Michael Buen

นี่เป็นความคิดที่แย่มากโดยนักออกแบบ PostgreSQL มันสับสนทันทีที่คุณพยายามGROUP BYแสดงออกใด ๆ ที่มีฟังก์ชั่นรวมหรือฟังก์ชั่นหน้าต่างซึ่ง "เห็นได้ชัด" ไม่ทำงาน
Lukas Eder

13

SQL Server ไม่อนุญาตให้คุณอ้างอิงนามแฝงในกลุ่มตามข้อเนื่องจากเหตุผลทางตรรกะของการประมวลผล GROUP BY clause ถูกประมวลผลก่อน SELECT clause ดังนั้นจึงไม่รู้จักนามแฝงเมื่อ GROUP BY clause ได้รับการประเมิน นอกจากนี้ยังอธิบายว่าทำไมคุณสามารถใช้นามแฝงในข้อ ORDER BY

นี่คือหนึ่งในแหล่งที่มาของข้อมูลในSQL Server ขั้นตอนการประมวลผลเชิงตรรกะ


8

ฉันไม่ได้ตอบว่าทำไมถึงเป็นเช่นนั้น แต่ต้องการแสดงวิธีแก้ไขข้อ จำกัด ใน SQL Server โดยใช้CROSS APPLYเพื่อสร้างนามแฝง จากนั้นคุณใช้มันในGROUP BYข้อเช่น:

SELECT 
 itemName as ItemName,
 FirstLetter,
 Count(itemName)
FROM table1
CROSS APPLY (SELECT substring(itemName, 1,1) as FirstLetter) Alias
GROUP BY itemName, FirstLetter

4

ข้อควรระวังว่าการใช้ชื่อแทนใน Group By (สำหรับบริการที่สนับสนุนเช่น postgres) อาจมีผลลัพธ์ที่ไม่ได้ตั้งใจ ตัวอย่างเช่นถ้าคุณสร้างนามแฝงที่มีอยู่แล้วในคำสั่งภายในกลุ่มตามจะเลือกชื่อฟิลด์ภายใน

-- Working example in postgres
select col1 as col1_1, avg(col3) as col2_1
from
    (select gender as col1, maritalstatus as col2, 
    yearlyincome as col3 from customer) as layer_1
group by col1_1;

-- Failing example in postgres
select col2 as col1, avg(col3)
from
    (select gender as col1, maritalstatus as col2,
    yearlyincome as col3 from customer) as layer_1
group by col1;

3

DBMS บางตัวจะให้คุณใช้นามแฝงแทนการทำซ้ำนิพจน์ทั้งหมด
Teradata เป็นตัวอย่างหนึ่ง

ฉันหลีกเลี่ยงสัญลักษณ์แสดงตำแหน่งตามที่ Bill แนะนำตามเหตุผลที่บันทึกไว้ในคำถาม SOนี้

ทางเลือกที่ง่ายและมีประสิทธิภาพคือการทำซ้ำการแสดงออกในกลุ่มตามข้อ
DRY ใช้ไม่ได้กับ SQL


1

ระวังการใช้นามแฝงเมื่อจัดกลุ่มผลลัพธ์จากมุมมองใน SQLite คุณจะได้รับผลลัพธ์ที่ไม่คาดคิดหากชื่อนามแฝงเหมือนกับชื่อคอลัมน์ของตารางต้นแบบใด ๆ (ไปยังมุมมอง)


0

ย้อนกลับไปในวันที่ฉันพบว่า Rdb ผลิตภัณฑ์ DEC เดิมที่ Oracle สนับสนุนในขณะนี้อนุญาตให้ใช้ชื่อแทนคอลัมน์ใน GROUP BY Mainstream Oracle ผ่านเวอร์ชัน 11 ไม่อนุญาตให้ใช้นามแฝงคอลัมน์ใน GROUP BY ไม่แน่ใจว่า Postgresql, SQL Server, MySQL, อื่น ๆ จะอนุญาตหรือไม่อนุญาต YMMV

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.