จะใช้ DISTINCT และ ORDER BY ในคำสั่ง SELECT เดียวกันได้อย่างไร


117

หลังจากดำเนินการคำสั่งต่อไปนี้:

SELECT  Category  FROM MonitoringJob ORDER BY CreationDate DESC

ฉันได้รับค่าต่อไปนี้จากฐานข้อมูล:

test3
test3
bildung
test4
test3
test2
test1

แต่ฉันต้องการลบรายการที่ซ้ำกันดังนี้:

bildung
test4
test3
test2
test1

ฉันพยายามใช้ DISTINCT แต่ใช้ไม่ได้กับ ORDER BY ในคำสั่งเดียว กรุณาช่วย.

สำคัญ:

  1. ฉันลองใช้:

    SELECT DISTINCT Category FROM MonitoringJob ORDER BY CreationDate DESC

    มันไม่ทำงาน

  2. Order by CreationDate มีความสำคัญมาก


1
ยังไงมันก็ไม่ได้ เอาต์พุตผิด?
Fedearne

คำตอบ:


195

ปัญหาคือคอลัมน์ที่ใช้ในORDER BYไม่ได้ระบุไว้ในไฟล์DISTINCT. ในการดำเนินการนี้คุณต้องใช้ฟังก์ชันการรวมเพื่อจัดเรียงและใช้ a GROUP BYเพื่อDISTINCTทำงาน

ลองทำสิ่งนี้:

SELECT DISTINCT Category, MAX(CreationDate) 
FROM MonitoringJob 
GROUP BY Category 
ORDER BY MAX(CreationDate) DESC, Category

99
คุณไม่จำเป็นต้องใช้คีย์เวิร์ด DISTINCT ด้วยซ้ำหากคุณจัดกลุ่มตามหมวดหมู่
MatBailie

18

คอลัมน์คีย์การจัดเรียงแบบขยาย

สาเหตุที่สิ่งที่คุณต้องการทำไม่ได้ผลเป็นเพราะลำดับตรรกะของการดำเนินการใน SQLซึ่งสำหรับแบบสอบถามแรกของคุณคือ (แบบง่าย):

  • FROM MonitoringJob
  • SELECT Category, CreationDateเช่นเพิ่มคอลัมน์คีย์การจัดเรียงแบบขยายที่เรียกว่า
  • ORDER BY CreationDate DESC
  • SELECT Categoryเช่นลบคอลัมน์คีย์การเรียงลำดับเพิ่มเติมอีกครั้งจากผลลัพธ์

ดังนั้นด้วยคุณลักษณะคอลัมน์คีย์การเรียงลำดับแบบขยายมาตรฐานของ SQL จึงเป็นไปได้โดยสิ้นเชิงที่จะเรียงลำดับตามสิ่งที่ไม่อยู่ในSELECTอนุประโยคเนื่องจากมีการเพิ่มไว้ชั่วคราวในเบื้องหลัง

แล้วทำไมถึงใช้ไม่ได้กับDISTINCT?

หากเราเพิ่มการDISTINCTดำเนินการจะเพิ่มระหว่างSELECTและORDER BY:

  • FROM MonitoringJob
  • SELECT Category, CreationDate
  • DISTINCT
  • ORDER BY CreationDate DESC
  • SELECT Category

แต่ตอนนี้ด้วยคอลัมน์คีย์การจัดเรียงแบบขยาย CreationDateความหมายของการDISTINCTดำเนินการได้เปลี่ยนไปดังนั้นผลลัพธ์จะไม่เหมือนเดิมอีกต่อไป นี่ไม่ใช่สิ่งที่เราต้องการดังนั้นทั้งมาตรฐาน SQL และฐานข้อมูลที่เหมาะสมทั้งหมดจึงห้ามการใช้งานนี้

วิธีการแก้ปัญหา

สามารถจำลองด้วยไวยากรณ์มาตรฐานได้ดังนี้

SELECT Category
FROM (
  SELECT Category, MAX(CreationDate) AS CreationDate
  FROM MonitoringJob
  GROUP BY Category
) t
ORDER BY CreationDate DESC

หรือเพียงแค่ (ในกรณีนี้) ดังที่แสดงโดยPrutswonder

SELECT Category, MAX(CreationDate) AS CreationDate
FROM MonitoringJob
GROUP BY Category
ORDER BY CreationDate DESC

ฉันได้ blogged เกี่ยวกับ SQL ที่แตกต่างและ ORDER BY อื่น ๆ ในรายละเอียดที่นี่


1
ฉันคิดว่าคุณเข้าใจผิดเกี่ยวกับวิธีการDISTINCT ONทำงานและค่อนข้างแน่ใจว่ามันไม่ได้ช่วยตรงนี้ นิพจน์ในวงเล็บคือสิ่งที่ใช้เพื่อกำหนดความแตกต่าง (เงื่อนไขการจัดกลุ่ม) หากมีหมวดหมู่ที่แตกต่างกันที่เหมือนกันCreationDateจะมีเพียงหมวดหมู่เดียวเท่านั้นที่ปรากฏในผลลัพธ์ เนื่องจากฉันสงสัยว่าฉันอาจจะผิดหรือไม่ฉันจึงโหลดฐานข้อมูลตัวอย่างในโพสต์บล็อกของคุณเพื่อตรวจสอบอีกครั้ง: DISTINCT ONแบบสอบถามที่คุณให้ไว้นั้นสร้างผลลัพธ์ทั้งหมด 1,000 รายการ (มีจำนวนที่ซ้ำกันมากมายlength) ในขณะที่ข้อความค้นหาด้านล่างให้ เพียง 140 (ไม่ซ้ำกัน) ค่า
Inkling

@Inkling: ขอบคุณที่สละเวลา OP ต้องการให้นำ "รายการที่ซ้ำกัน" ออกอย่างชัดเจน ดู OP ของถ้อยคำ"แต่ฉันต้องการที่ซ้ำกันออกเช่นนี้" คุณอาจทำผิดพลาดเมื่อคัดลอกข้อความค้นหาจากบล็อกโพสต์ของฉัน มีสองคำสั่งอย่างใดอย่างหนึ่งที่ใช้DISTINCT(ไม่ON) DISTINCT ONและคนที่ใช้ โปรดสังเกตว่าส่วนหลังอย่างชัดเจนไม่ได้ลบความยาวที่ซ้ำกันออก แต่มีชื่อเรื่องที่ซ้ำกัน ฉันคิดว่าคำตอบของฉันที่นี่ถูกต้องทั้งหมด
Lukas Eder

1
ประเด็นของฉันคือDISTINCT ONเงื่อนไขของคุณกำลังลบรายการที่ซ้ำกันโดยใช้เงื่อนไขที่ไม่ถูกต้อง ในบล็อกของคุณโพสต์DISTINCT ONข้อความค้นหาจะลบชื่อเรื่องที่ซ้ำกันออกไปอย่างไรก็ตามDISTINCTข้อความค้นหาด้านบนและข้อความค้นหาด้านล่าง (ซึ่งคุณอ้างว่าเป็น "ไวยากรณ์น้ำตาล" สำหรับ) ทั้งสองจะลบความยาวที่ซ้ำกันออกเนื่องจากน่าจะเป็นเป้าหมายทั้งหมด สิ่งเดียวกันกับที่นี่: OP ต้องการให้ลบหมวดหมู่ที่ซ้ำกันออกไม่ใช่CreationDates ที่ซ้ำกันเหมือนที่DISTINCT ONแบบสอบถามทำ ถ้าคุณยังไม่เชื่อฉันลองทดสอบด้วยตัวคุณเอง
Inkling

6

หากไม่ต้องการผลลัพธ์ของ MAX (CreationDate) - เหมือนในตัวอย่างของคำถามเดิมคำตอบเดียวคือคำสั่งที่สองของคำตอบของ Prashant Gupta:

SELECT [Category] FROM [MonitoringJob] 
GROUP BY [Category] ORDER BY MAX([CreationDate]) DESC

คำอธิบาย: คุณไม่สามารถใช้คำสั่ง ORDER BY ในฟังก์ชันอินไลน์ได้ดังนั้นคำสั่งในคำตอบของ Prutswonder จึงไม่สามารถใช้งานได้ในกรณีนี้คุณไม่สามารถใส่การเลือกภายนอกรอบ ๆ และทิ้งส่วน MAX (CreationDate)


2

เพียงใช้รหัสนี้หากคุณต้องการค่าของคอลัมน์ [Category] และ [CreationDate]

SELECT [Category], MAX([CreationDate]) FROM [MonitoringJob] 
             GROUP BY [Category] ORDER BY MAX([CreationDate]) DESC

หรือใช้รหัสนี้หากคุณต้องการเฉพาะค่าของคอลัมน์ [หมวดหมู่]

SELECT [Category] FROM [MonitoringJob] 
GROUP BY [Category] ORDER BY MAX([CreationDate]) DESC

คุณจะมีบันทึกที่แตกต่างกันทั้งหมดที่คุณต้องการ


วงเล็บปีกกา [] เหล่านั้นสับสนโดยสิ้นเชิง ... ไวยากรณ์ SQL ที่ถูกต้องนี้หรือไม่
m13r

1
วงเล็บมีไว้สำหรับการหลีกเลี่ยงคำหลักเช่นลำดับเหตุการณ์ ฯลฯ ดังนั้นหากคุณมี (ตัวอย่าง) คอลัมน์ในตารางที่เรียกว่าEventคุณสามารถเขียน[Event]แทนที่จะEventหยุด SQL ที่ส่งข้อผิดพลาดในการแยกวิเคราะห์
Ben Maxfield

1

2) Order by CreationDate มีความสำคัญมาก

ผลการศึกษาเดิมระบุว่า "test3" มีผลลัพธ์หลายรายการ ...

ง่ายมากที่จะเริ่มใช้ MAX ตลอดเวลาเพื่อลบรายการที่ซ้ำกันใน Group By ... และลืมหรือเพิกเฉยต่อคำถามที่เป็นพื้นฐาน ...

OP คงตระหนักว่าการใช้ MAX ทำให้เขา "สร้าง" ครั้งสุดท้ายและการใช้ MIN จะทำให้ "สร้าง" ครั้งแรก ...


3
สิ่งนี้ดูเหมือนจะไม่ตอบคำถามจริงๆดูเหมือนว่าจะเป็นความคิดเห็นเกี่ยวกับการใช้MAXคำตอบของผู้ให้คำตอบคนอื่น ๆแทนที่จะเป็นสิ่งที่เป็นคำตอบสำหรับคำถาม
DaveyDaveDave

0
if object_id ('tempdb..#tempreport') is not null
begin  
drop table #tempreport
end 
create table #tempreport (
Category  nvarchar(510),
CreationDate smallint )
insert into #tempreport 
select distinct Category from MonitoringJob (nolock) 
select * from #tempreport  ORDER BY CreationDate DESC

0

ตามแบบสอบถามย่อยควรใช้งานได้:

    SELECT distinct(Category) from MonitoringJob  where Category in(select Category from MonitoringJob order by CreationDate desc);

อืมม ... ฉันไม่คิดว่ามันจะ ไม่ได้เรียงลำดับการเลือกภายนอก
Hossam El-Deen

มันจะไม่ทำงานฉันอยู่ที่นี่เพราะมันไม่ทำงาน
Amirreza

-1

แตกต่างจะเรียงลำดับระเบียนจากน้อยไปมาก หากคุณต้องการเรียงลำดับตามลำดับให้ใช้:

SELECT DISTINCT Category
FROM MonitoringJob
ORDER BY Category DESC

หากคุณต้องการเรียงลำดับเร็กคอร์ดตามฟิลด์ CreationDate ฟิลด์นี้จะต้องอยู่ในคำสั่ง select:

SELECT DISTINCT Category, creationDate
FROM MonitoringJob
ORDER BY CreationDate DESC

12
สิ่งนี้จะดำเนินการ แต่จะไม่ให้สิ่งที่ OP ต้องการ OP ต้องการหมวดหมู่ที่แตกต่างกันไม่ใช่การรวมหมวดหมู่และ CreateDate ที่แตกต่างกัน รหัสนี้สามารถแสดงผลได้หลายอินสแตนซ์ของหมวดหมู่เดียวกันโดยแต่ละรายการมีค่า CreationDate ที่แตกต่าง
MatBailie

-1

คุณสามารถใช้ CTE:

WITH DistinctMonitoringJob AS (
    SELECT DISTINCT Category Distinct_Category FROM MonitoringJob 
)

SELECT Distinct_Category 
FROM DistinctMonitoringJob 
ORDER BY Distinct_Category DESC

-3

ลองต่อไป แต่ไม่มีประโยชน์สำหรับข้อมูลขนาดใหญ่ ...

SELECT DISTINCT Cat FROM (
  SELECT Category as Cat FROM MonitoringJob ORDER BY CreationDate DESC
);

4
"คำสั่ง ORDER BY ไม่ถูกต้องในมุมมองฟังก์ชันแบบอินไลน์ตารางที่ได้รับแบบสอบถามย่อยและนิพจน์ทั่วไปของตารางเว้นแต่จะระบุ TOP หรือ FOR XML ไว้ด้วย"
TechplexEngineer

ไม่ได้ผลเนื่องจากคุณไม่ได้ระบุคอลัมน์ CreationDate ตามลำดับโดย
Mauro Bilotti

1
@TechplexEngineer ความคิดเห็นของคุณไม่ถูกต้อง การใช้ORDER BYในแบบสอบถามย่อยนั้นใช้ได้อย่างแน่นอน และบางคนก็โหวตความคิดเห็นที่ไม่ถูกต้องของคุณด้วย
Racil Hilan

ฉันกำลังลองสิ่งนี้และมีข้อผิดพลาดเดียวกันกับ @TechplexEngineer ฉันใช้คำสั่งซื้อที่กำหนดเองกับกรณีเมื่อ
เอจเบย์รัค

-4

สามารถทำได้โดยใช้แบบสอบถามภายในเช่นนี้

$query = "SELECT * 
            FROM (SELECT Category  
                FROM currency_rates                 
                ORDER BY id DESC) as rows               
            GROUP BY currency";

-5
SELECT DISTINCT Category FROM MonitoringJob ORDER BY Category ASC

2
ต้องจัดเรียงตามวันที่สร้าง !! มันสำคัญมาก
rr

ดังนั้นจึงเป็นไปไม่ได้ที่จะเพิ่มคอลัมน์ที่คุณต้องการสั่งซื้อด้วยตัวเอง? ตัวอย่างของคุณแสดงรายการที่เรียงลำดับตามตัวอักษร หากคุณต้องการสั่งซื้อตามวันที่สร้างก็เพิ่มเข้าไป จริงๆมันไม่ยากเลย
Furicane

8
-1: OP พยายามแล้วก็ไม่ได้ผลเพราะมันเป็นไปไม่ได้และดูเหมือนคุณจะละเลยข้อเท็จจริงนั้นเมื่ออุปถัมภ์ OP ประเด็นคือตัวดำเนินการ DISTINCT จะตรวจสอบหลายระเบียนที่มีค่า Category เดียวกันซึ่งแต่ละระเบียนอาจมีวันที่สร้างที่แตกต่างกัน ดังนั้นจึงเป็นไปไม่ได้ในเชิงเหตุผลเมื่อใช้ DISTINCT สิ่งนี้จะผลักตรรกะที่ต้องการไปยัง GROUP BY แทนที่จะเป็น DISTINCT ทำให้สามารถรวม (MAX) ในวันที่สร้างได้
MatBailie

ที่จริงแล้วถ้าคุณลองดูสิ่งที่ OP ทำซึ่งผิดรูปแบบอย่างสมบูรณ์ SQL - ฉันไม่ได้ทำผิดพลาดแม้แต่ครั้งเดียวและผลลัพธ์ที่ได้ก็ตรงกับที่เขาร้องขอ ฉันจะไม่รบกวน -1 เพียงแค่อ่านครั้งต่อไปก่อนที่จะแก้ไขคน ขอบคุณ.
Furicane

8
คุณแนะนำให้เพิ่มช่อง CreationDate โดยตรงแม้จะบอกว่า "มันไม่ยากจริงๆ" การทำเช่นนั้นทำให้ SQL ผิดรูปแบบ คุณได้รับ -1 สำหรับการอุปถัมภ์ OP โดยให้คำแนะนำที่จะนำ OP กลับไปสู่คำแถลงที่เขาโพสต์ไว้ในตอนแรกและไม่สังเกตเห็นความขัดแย้งระหว่าง DISTINCT และการสั่งซื้อโดยฟิลด์ที่ไม่อยู่ใน DISTINCT นอกจากนี้ 'b' มาก่อน 't' และ '1' มาก่อน '4' ดังนั้นผลลัพธ์ที่ได้จาก OP จึงไม่จัดเรียงตามลำดับตัวอักษร ฉันขอแนะนำคำแนะนำของคุณเองแล้ว: อ่าน (อย่างรอบคอบมากขึ้น) ในครั้งต่อไป
MatBailie
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.