การเรียงลำดับแบบไดนามิกภายใน SQL Stored Procedures


126

นี่เป็นปัญหาที่ฉันใช้เวลาหลายชั่วโมงในการค้นคว้าในอดีต สำหรับฉันแล้วดูเหมือนว่าจะเป็นสิ่งที่ควรได้รับการแก้ไขโดยโซลูชันRDBMS ที่ทันสมัยแต่ฉันยังไม่พบสิ่งใดที่ตอบสนองสิ่งที่ฉันเห็นว่าเป็นความต้องการทั่วไปอย่างไม่น่าเชื่อในเว็บหรือแอปพลิเคชัน Windows ที่มีฐานข้อมูลส่วนหลัง

ฉันพูดถึงการเรียงลำดับแบบไดนามิก ในโลกแฟนตาซีของฉันมันควรจะเรียบง่ายเหมือนกับ:

ORDER BY @sortCol1, @sortCol2

นี่คือตัวอย่างมาตรฐานที่กำหนดโดยผู้พัฒนา SQL มือใหม่และStored Procedureทั่วฟอรัมต่างๆบนอินเทอร์เน็ต "ทำไมถึงทำไม่ได้" พวกเขาถาม. ในที่สุดก็มีใครบางคนมาบรรยายเกี่ยวกับลักษณะการรวบรวมของขั้นตอนการจัดเก็บแผนการดำเนินการโดยทั่วไปและเหตุผลอื่น ๆ อีกมากมายว่าทำไมจึงไม่สามารถใส่พารามิเตอร์ลงในORDER BYประโยคได้โดยตรง


ฉันรู้ว่าพวกคุณบางคนกำลังคิดอะไรอยู่แล้ว: "ให้ลูกค้าจัดการเรียงลำดับ" โดยปกติแล้วสิ่งนี้จะลดการทำงานออกจากฐานข้อมูลของคุณ ในกรณีของเราเซิร์ฟเวอร์ฐานข้อมูลของเราไม่ได้ทำลายเหงื่อ 99% ของเวลาและยังไม่ได้เป็นแบบมัลติคอร์หรือการปรับปรุงสถาปัตยกรรมระบบอื่น ๆ อีกมากมายที่เกิดขึ้นทุกๆ 6 เดือน ด้วยเหตุนี้เพียงอย่างเดียวการมีฐานข้อมูลของเราจัดการกับการเรียงลำดับจะไม่เป็นปัญหา นอกจากนี้ฐานข้อมูลเป็นอย่างมากเก่งในการจัดเรียง พวกเขาได้รับการปรับให้เหมาะสมและใช้เวลาหลายปีในการทำให้ถูกต้องภาษาที่ใช้ทำนั้นมีความยืดหยุ่นใช้งานง่ายและเรียบง่ายและเหนือสิ่งอื่นใดนักเขียน SQL มือใหม่รู้วิธีการทำและที่สำคัญยิ่งกว่านั้นพวกเขารู้วิธีแก้ไข ทำการเปลี่ยนแปลงทำการบำรุงรักษา ฯลฯ เมื่อฐานข้อมูลของคุณห่างไกลจากการถูกเก็บภาษีและคุณเพียงแค่ต้องการลดความซับซ้อนของเวลาในการพัฒนา (และย่น!) สิ่งนี้ดูเหมือนจะเป็นทางเลือกที่ชัดเจน

แล้วมีปัญหาเว็บ ฉันได้เล่นกับ JavaScript ที่จะทำการจัดเรียงตาราง HTML ฝั่งไคลเอ็นต์ แต่ก็ไม่สามารถยืดหยุ่นได้เพียงพอสำหรับความต้องการของฉันและอีกครั้งเนื่องจากฐานข้อมูลของฉันไม่ได้เก็บภาษีมากเกินไปและสามารถจัดเรียงได้อย่างง่ายดายจริงๆฉัน มีช่วงเวลาที่ยากลำบากในการระบุเวลาที่ต้องใช้ในการเขียนซ้ำหรือม้วนตัวเรียงลำดับ JavaScript ของฉันเอง โดยทั่วไปจะใช้กับการเรียงลำดับฝั่งเซิร์ฟเวอร์แม้ว่าจะเป็นที่ต้องการมากกว่า JavaScript อยู่แล้วก็ตาม ฉันไม่ใช่คนที่ชอบค่าใช้จ่ายของชุดข้อมูลเป็นพิเศษดังนั้นฟ้องฉัน

แต่สิ่งนี้ทำให้จุดที่เป็นไปไม่ได้กลับมา - หรือไม่ใช่เรื่องง่าย ฉันเคยทำกับระบบก่อนหน้านี้เป็นวิธีแฮ็คที่เหลือเชื่อในการจัดเรียงแบบไดนามิก มันไม่สวยหรือใช้งานง่ายเรียบง่ายหรือยืดหยุ่นและนักเขียน SQL มือใหม่จะหายไปภายในไม่กี่วินาที สิ่งนี้ดูเหมือนจะไม่ใช่ "วิธีแก้ปัญหา" มากนัก แต่เป็น "ภาวะแทรกซ้อน"


ตัวอย่างต่อไปนี้ไม่ได้มีไว้เพื่อแสดงแนวทางปฏิบัติที่ดีที่สุดหรือรูปแบบการเข้ารหัสที่ดีหรือสิ่งใด ๆ และไม่ได้บ่งบอกถึงความสามารถของฉันในฐานะโปรแกรมเมอร์ T-SQL พวกเขาคือสิ่งที่พวกเขาเป็นและฉันยอมรับอย่างเต็มที่ว่าพวกเขาสับสนรูปแบบไม่ดีและเป็นเพียงการแฮ็กธรรมดา

เราส่งค่าจำนวนเต็มเป็นพารามิเตอร์ไปยังโพรซีเดอร์ที่เก็บไว้ (ขอเรียกพารามิเตอร์ว่า "sort") และจากนั้นเรากำหนดตัวแปรอื่น ๆ ตัวอย่างเช่น ... สมมติว่า sort คือ 1 (หรือค่าเริ่มต้น):

DECLARE @sortCol1 AS varchar(20)
DECLARE @sortCol2 AS varchar(20)
DECLARE @dir1 AS varchar(20)
DECLARE @dir2 AS varchar(20)
DECLARE @col1 AS varchar(20)
DECLARE @col2 AS varchar(20)

SET @col1 = 'storagedatetime';
SET @col2 = 'vehicleid';

IF @sort = 1                -- Default sort.
BEGIN
    SET @sortCol1 = @col1;
    SET @dir1 = 'asc';
    SET @sortCol2 = @col2;
    SET @dir2 = 'asc';
END
ELSE IF @sort = 2           -- Reversed order default sort.
BEGIN
    SET @sortCol1 = @col1;
    SET @dir1 = 'desc';
    SET @sortCol2 = @col2;
    SET @dir2 = 'desc';
END

คุณสามารถดูได้แล้วว่าถ้าฉันประกาศตัวแปร @colX เพิ่มเติมเพื่อกำหนดคอลัมน์อื่น ๆ ฉันจะสามารถสร้างสรรค์คอลัมน์เพื่อจัดเรียงตามค่าของ "sort" ได้อย่างไร ... ในการใช้งานมักจะมีลักษณะดังนี้ ประโยคที่ยุ่งอย่างไม่น่าเชื่อ:

ORDER BY
    CASE @dir1
        WHEN 'desc' THEN
            CASE @sortCol1
                WHEN @col1 THEN [storagedatetime]
                WHEN @col2 THEN [vehicleid]
            END
    END DESC,
    CASE @dir1
        WHEN 'asc' THEN
            CASE @sortCol1
                WHEN @col1 THEN [storagedatetime]
                WHEN @col2 THEN [vehicleid]
            END
    END,
    CASE @dir2
        WHEN 'desc' THEN
            CASE @sortCol2
                WHEN @col1 THEN [storagedatetime]
                WHEN @col2 THEN [vehicleid]
            END
    END DESC,
    CASE @dir2
        WHEN 'asc' THEN
            CASE @sortCol2
                WHEN @col1 THEN [storagedatetime]
                WHEN @col2 THEN [vehicleid]
            END
    END

เห็นได้ชัดว่านี่เป็นตัวอย่างที่ถูกถอดออกมาก ของจริงเนื่องจากโดยปกติแล้วเราจะมีสี่หรือห้าคอลัมน์เพื่อรองรับการเรียงลำดับโดยแต่ละคอลัมน์จะมีคอลัมน์รองหรือแม้แต่คอลัมน์ที่สามที่เป็นไปได้ที่จะจัดเรียงนอกเหนือจากนั้น (เช่นวันที่จากมากไปหาน้อยจากนั้นเรียงลำดับที่สองตามชื่อจากน้อยไปหามาก) และแต่ละคอลัมน์รองรับ bi- การเรียงลำดับตามทิศทางซึ่งเพิ่มจำนวนเคสได้เป็นสองเท่า ใช่ ... มันมีขนขึ้นอย่างรวดเร็ว

แนวคิดก็คือเราสามารถ "เปลี่ยนกรณีการจัดเรียง" ได้อย่างง่ายดายเพื่อให้ vehicleid ถูกจัดเรียงก่อนเวลาจัดเก็บข้อมูล ... แต่ความยืดหยุ่นหลอกอย่างน้อยในตัวอย่างง่ายๆนี้ก็จบลงที่นั่นจริงๆ โดยพื้นฐานแล้วแต่ละกรณีที่ไม่ผ่านการทดสอบ (เนื่องจากวิธีการเรียงลำดับของเราใช้ไม่ได้ในเวลานี้) จะแสดงค่าเป็น NULL ดังนั้นคุณจึงจบลงด้วยประโยคที่ทำหน้าที่ดังต่อไปนี้:

ORDER BY NULL DESC, NULL, [storagedatetime] DESC, blah blah

คุณจะได้รับความคิด ทำงานได้เนื่องจาก SQL Server ละเว้นค่า null อย่างมีประสิทธิภาพตามลำดับ นี่เป็นเรื่องยากที่จะรักษาอย่างไม่น่าเชื่อเนื่องจากทุกคนที่มีความรู้พื้นฐานเกี่ยวกับ SQL อาจเห็นได้ ถ้าฉันสูญเสียคุณไปอย่ารู้สึกแย่ เราใช้เวลานานในการทำให้มันใช้งานได้และเรายังคงสับสนในการพยายามแก้ไขหรือสร้างขึ้นใหม่เช่นนี้ โชคดีที่ไม่จำเป็นต้องเปลี่ยนบ่อยๆมิฉะนั้นจะกลายเป็น "ไม่คุ้มกับปัญหา" อย่างรวดเร็ว

มันได้ผล


คำถามของฉันคือ: มีวิธีที่ดีกว่านี้หรือไม่?

ฉันโอเคกับโซลูชันอื่นที่ไม่ใช่ขั้นตอนที่เก็บไว้เนื่องจากฉันรู้ว่ามันอาจไม่ใช่วิธีที่จะไป โดยเฉพาะอย่างยิ่งฉันต้องการทราบว่ามีใครทำได้ดีกว่านี้ภายใน Stored Procedure แต่ถ้าไม่คุณจะจัดการอย่างไรให้ผู้ใช้จัดเรียงตารางข้อมูลแบบไดนามิก (แบบสองทิศทางด้วย) ด้วย ASP.NET

และขอขอบคุณที่อ่าน (หรืออย่างน้อยก็อ่าน) คำถามยาว ๆ !

PS: ดีใจที่ฉันไม่ได้แสดงตัวอย่างของขั้นตอนการจัดเก็บที่รองรับการเรียงลำดับแบบไดนามิกการกรองแบบไดนามิก / การค้นหาข้อความของคอลัมน์การแบ่งหน้าผ่าน ROWNUMBER () OVER และลอง ... จับด้วยการย้อนธุรกรรมเมื่อเกิดข้อผิดพลาด ... "behemoth-sized" ไม่ได้เริ่มอธิบายด้วยซ้ำ


ปรับปรุง:

  • ฉันต้องการที่จะหลีกเลี่ยงการ SQL การแยกสตริงเข้าด้วยกันและเรียกใช้ EXEC กับมันเอาชนะวัตถุประสงค์ของการจัดเก็บโพรซีเดอร์ไว้ตั้งแต่แรก บางครั้งฉันก็สงสัยว่าข้อเสียของการทำสิ่งนั้นจะไม่คุ้มค่าหรือไม่อย่างน้อยในกรณีการเรียงลำดับไดนามิกพิเศษเหล่านี้ ถึงกระนั้นฉันก็มักจะรู้สึกสกปรกทุกครั้งที่ทำสตริง SQL แบบไดนามิกเช่นนั้นเหมือนฉันยังคงอยู่ในโลก ASP แบบคลาสสิก
  • จำนวนมากของเหตุผลที่เราต้องการวิธีการจัดเก็บในสถานที่แรกสำหรับการรักษาความปลอดภัย ฉันไม่ได้รับสายเกี่ยวกับข้อกังวลด้านความปลอดภัยขอแนะนำวิธีแก้ไขเท่านั้น ด้วย SQL Server 2005 เราสามารถตั้งค่าการอนุญาต (ตามผู้ใช้แต่ละรายหากจำเป็น) ที่ระดับสคีมาบนโพรซีเดอร์ที่จัดเก็บแต่ละโพรซีเดอร์จากนั้นปฏิเสธการสืบค้นใด ๆ กับตารางโดยตรง การวิพากษ์วิจารณ์ข้อดีข้อเสียของแนวทางนี้อาจเป็นคำถามอื่น แต่ก็ไม่ใช่การตัดสินใจของฉันอีกครั้ง ฉันเป็นแค่ลิงรหัสผู้นำ :)

อ้างถึงstackoverflow.com/questions/3659981/…ด้วย - SQL Server dynamic ORDER BY with mixed datatypes
LCJ

Dynamic SQL เป็นวิธีที่เหนือกว่าของ FAR ... IF [และนี่คือ IF ขนาดใหญ่] .. Data Access Layer ของคุณมีความเข้มงวดและ Dynamic SQL ของคุณถูกสร้างขึ้นโดยระบบที่ตั้งโปรแกรมอย่างเข้มงวดด้วยกฎ RDBMS ที่แสดงในรูปแบบที่สมบูรณ์แบบ สถาปัตยกรรมฐานข้อมูลที่ออกแบบโดยอัลกอริทึมเป็นสิ่งที่สวยงาม ...
hajikelist

คำตอบ:


97

ใช่มันเป็นความเจ็บปวดและวิธีที่คุณทำมันดูเหมือนกับสิ่งที่ฉันทำ:

order by
case when @SortExpr = 'CustomerName' and @SortDir = 'ASC' 
    then CustomerName end asc, 
case when @SortExpr = 'CustomerName' and @SortDir = 'DESC' 
    then CustomerName end desc,
...

สำหรับฉันสิ่งนี้ยังดีกว่าการสร้าง SQL แบบไดนามิกจากโค้ดซึ่งกลายเป็นฝันร้ายในการปรับขนาดและการบำรุงรักษาสำหรับ DBA

สิ่งที่ฉันทำจากรหัสคือ refactor เพจจิ้งและการเรียงลำดับดังนั้นฉันอย่างน้อยไม่ได้มีจำนวนมากของการทำซ้ำมีกับประชากรของค่าและ@SortExpr@SortDir

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


1
เผง เป้าหมายของฉันคือหลีกเลี่ยงการทำคำสั่ง EXEC บนสตริง varchar ขนาดใหญ่ 5,000 ตัว ทุกสิ่งที่เราทำจะต้องทำผ่านโพรซีเดอร์ที่จัดเก็บไว้หากเพียงเพื่อความปลอดภัยที่เพิ่มเข้ามาเนื่องจากเราสามารถตั้งค่าสิทธิ์ในระดับสคีมาได้ ความสามารถในการปรับขนาดและประสิทธิภาพที่เพิ่มขึ้นเป็นเพียงข้อดีในกรณีของเรา
Sean Hanley

1
เพิ่มความสามารถในการบำรุงรักษาให้กับ {security, scalability, performance} เมื่อคุณมีแอพ 3 หรือ 4 แอพที่มีไดนามิก SQL ที่รันกับฐานข้อมูลของคุณคุณจะเมาคุณจะไม่สามารถเปลี่ยนแปลงอะไรได้โดยเฉพาะอย่างยิ่งเมื่อแอพมีอายุมากขึ้นและนักพัฒนาก็ดำเนินต่อไป exec และ dynamic sql นั้นชั่วร้าย
Eric Z Beard

นั่นเป็นเพียงแค่นั้น - เราทำไปแล้วตั้งแต่ก่อนที่จะมาถึงที่นี่สำหรับเว็บแอป Classic ASP ทั้งหมดที่ยังคงทำงานอยู่และแอป Access VB จำนวนมากยังคงหมุนเวียนอยู่ ฉันกระตุกและต้องอดกลั้นความต้องการที่จะแก้ไขข้อผิดพลาดที่เห็นได้ชัดทุกครั้งที่ฉันต้องทำการบำรุงรักษาใด ๆ
Sean Hanley

1
นี่คือสิ่งที่ฉันทำเช่นกันยกเว้นฉันเข้ารหัสทิศทางเป็น SortExpr: ORDER BY CASE WHEN sort = 'FirstName' แล้ว FirstName END ASC, CASE WHEN sort = '-FirstName' แล้ว FirstName END DESC
Michael Bray

นี่คือฝันร้ายสำหรับ DBA และวิศวกรซอฟต์แวร์เหมือนกัน ดังนั้นแทนที่จะสามารถมีระบบไดนามิก แต่เข้มงวดที่สร้างคำสั่ง SQL ที่แสดงออกโดยอิงจากสคีมาข้อมูลของคุณคุณมี glop ที่น่าขยะแขยงของการพูดพล่อยๆแบบฮาร์ดโค้ด เป็นการเขียนโปรแกรมที่แย่และดีที่สุด
hajikelist

23

วิธีนี้ช่วยให้คอลัมน์ที่เรียงลำดับได้ไม่ซ้ำกันสองครั้งตามลำดับและเป็น IMO ที่อ่านง่ายขึ้นเล็กน้อย:

SELECT
  s.*
FROM
  (SELECT
    CASE @SortCol1
      WHEN 'Foo' THEN t.Foo
      WHEN 'Bar' THEN t.Bar
      ELSE null
    END as SortCol1,
    CASE @SortCol2
      WHEN 'Foo' THEN t.Foo
      WHEN 'Bar' THEN t.Bar
      ELSE null
    END as SortCol2,
    t.*
  FROM
    MyTable t) as s
ORDER BY
  CASE WHEN @dir1 = 'ASC'  THEN SortCol1 END ASC,
  CASE WHEN @dir1 = 'DESC' THEN SortCol1 END DESC,
  CASE WHEN @dir2 = 'ASC'  THEN SortCol2 END ASC,
  CASE WHEN @dir2 = 'DESC' THEN SortCol2 END DESC

ดูเหมือนจะเป็นคำตอบที่ดี แต่ดูเหมือนจะไม่ได้ผลเมื่อคอลัมน์ที่จัดเรียงได้มีประเภทข้อมูลที่แตกต่างกัน
SlimSim

6

Dynamic SQL ยังคงเป็นตัวเลือก คุณต้องตัดสินใจว่าตัวเลือกนั้นถูกปากกว่าสิ่งที่คุณมีอยู่ในปัจจุบันหรือไม่

นี่คือบทความที่แสดงให้เห็นว่า: http://www.4guysfromrolla.com/webtech/010704-1.shtml


6

แอปพลิเคชันของฉันทำสิ่งนี้ได้มาก แต่ทั้งหมดกำลังสร้าง SQL แบบไดนามิก อย่างไรก็ตามเมื่อฉันจัดการกับขั้นตอนการจัดเก็บฉันทำสิ่งนี้:

  1. ทำให้กระบวนงานที่จัดเก็บเป็นฟังก์ชันที่ส่งคืนตารางค่าของคุณ - ไม่ต้องเรียงลำดับ
  2. จากนั้นในรหัสแอปพลิเคชันของselect * from dbo.fn_myData() where ... order by ...คุณคุณสามารถระบุลำดับการจัดเรียงได้แบบไดนามิกที่นั่น

จากนั้นอย่างน้อยส่วนไดนามิกก็อยู่ในแอปพลิเคชันของคุณ แต่ฐานข้อมูลยังคงดำเนินการอย่างหนัก


1
นั่นอาจเป็นการประนีประนอมที่ดีที่สุดที่ฉันเคยเห็นระหว่างการใช้ SQL แบบไดนามิกและกระบวนงานที่จัดเก็บไว้ด้วยกัน ฉันชอบมัน. ฉันอาจทดลองใช้วิธีการที่คล้ายกันในบางครั้ง แต่การเปลี่ยนแปลงดังกล่าวจะเป็นข้อห้ามในโครงการที่กำลังดำเนินอยู่ของเรา
Sean Hanley

1
คุณสามารถบรรลุสิ่งเดียวกันได้โดยใช้ตัวแปรตารางภายในแทนฟังก์ชันตารางที่ส่งคืนข้อมูล ฉันพบว่าตารางในเครื่องมีความยืดหยุ่นมากกว่าฟังก์ชันเนื่องจากคุณสามารถแสดงข้อมูลการดีบักได้
Sanjay Zalke

5

เทคนิคขั้นตอนการจัดเก็บ (แฮ็ก?) ที่ฉันเคยใช้เพื่อหลีกเลี่ยงไดนามิก SQL สำหรับงานบางอย่างคือการมีคอลัมน์การจัดเรียงที่ไม่ซ้ำกัน กล่าวคือ

SELECT
   name_last,
   name_first,
   CASE @sortCol WHEN 'name_last' THEN [name_last] ELSE 0 END as mySort
FROM
   table
ORDER BY 
    mySort

สิ่งนี้ง่ายต่อการเอาชนะในการส่ง - คุณสามารถเชื่อมต่อฟิลด์ในคอลัมน์ mySort ของคุณย้อนกลับลำดับด้วยฟังก์ชันคณิตศาสตร์หรือวันที่ ฯลฯ

โดยเฉพาะอย่างยิ่งฉันใช้กริดมุมมอง asp.net หรือวัตถุอื่น ๆ ที่มีการเรียงลำดับในตัวเพื่อทำการจัดเรียงให้ฉันหลังจากเรียกข้อมูลจาก Sql-Server หรือแม้ว่าจะไม่ได้อยู่ในตัว - เช่นดาต้าเบิล ฯลฯ ใน asp.net


4

คุณสามารถแฮ็คสิ่งนี้ได้หลายวิธี

วิชาบังคับก่อน:

  1. เพียงคำสั่ง SELECT เดียวใน sp
  2. ไม่ต้องเรียงลำดับใด ๆ (หรือมีค่าเริ่มต้น)

จากนั้นแทรกลงในตารางชั่วคราว:

create table #temp ( your columns )

insert #temp
exec foobar

select * from #temp order by whatever

วิธี # 2: ตั้งค่าเซิร์ฟเวอร์ที่เชื่อมโยงกลับไปที่ตัวเองจากนั้นเลือกจากสิ่งนี้โดยใช้ openquery: http://www.sommarskog.se/share_data.html#OPENQUERY


4

อาจมีตัวเลือกที่สามเนื่องจากเซิร์ฟเวอร์ของคุณมีรอบการสำรองข้อมูลจำนวนมากให้ใช้ขั้นตอนตัวช่วยในการจัดเรียงผ่านตารางชั่วคราว สิ่งที่ต้องการ

create procedure uspCallAndSort
(
    @sql varchar(2048),        --exec dbo.uspSomeProcedure arg1,'arg2',etc.
    @sortClause varchar(512)    --comma-delimited field list
)
AS
insert into #tmp EXEC(@sql)
declare @msql varchar(3000)
set @msql = 'select * from #tmp order by ' + @sortClause
EXEC(@msql)
drop table #tmp
GO

Caveat: ฉันยังไม่ได้ทดสอบ แต่มัน "ควร" ทำงานใน SQL Server 2005 (ซึ่งจะสร้างตารางชั่วคราวจากชุดผลลัพธ์โดยไม่ได้ระบุคอลัมน์ไว้ล่วงหน้า)


2

ในบางครั้งมันคุ้มค่าหรือไม่ที่จะย้ายออกจากขั้นตอนที่จัดเก็บไว้และเพียงแค่ใช้การสืบค้นแบบกำหนดพารามิเตอร์เพื่อหลีกเลี่ยงการแฮ็กเกอร์ประเภทนี้


1
ในบางกรณีอาจเป็นค้อนขนาดใหญ่บนตะปู แต่บ่อยครั้งที่เราต้องการตั้งค่าการอนุญาต (โดยเฉพาะอย่างยิ่งดำเนินการ) โดยตรงบนโพรซีเดอร์ที่เก็บไว้และไม่อนุญาตให้มีการสืบค้น SQL ใด ๆ กับตารางโดยตรงแม้แต่ SELECT ฉันไม่ชอบแฮ็คเกอร์มากนัก แต่ความปลอดภัยไม่ใช่สิ่งที่ฉันต้องทำ
Sean Hanley

1
ด้วยเหตุนี้ผู้คนจำนวนมากจึงเปลี่ยนไปใช้ Object Relational Mapping การเดินทางแบบไปกลับที่ไม่จำเป็นสำหรับการเรียงลำดับบล็อก CASE ขนาดใหญ่สำหรับการอัปเดตคอลัมน์จำนวนมากแบบเดียวกันอย่างไร้เหตุผลเมื่อจำเป็นต้องอัปเดตเพียงอันเดียวเท่านั้นข้อโต้แย้งที่ชนะสำหรับขั้นตอนการจัดเก็บที่ยังคงมีอยู่คือความปลอดภัย
Pittsburgh DBA

ฉันกำลังย้ายจาก ORM (EF) ไปยังขั้นตอนการจัดเก็บเนื่องจาก ORM ไม่รองรับการค้นหาข้อความแบบเต็ม
Ronnie Overby

@RonnieOverby การค้นหาข้อความแบบเต็มมักจะให้บริการที่ดีกว่าโดยโซลูชันเฉพาะเช่น Lucene
Hank Gay

@HankGay ฉันรู้สึกแปลก ๆ ที่เอนทิตีเฟรมเวิร์กไม่สนับสนุนลูซีนด้วย
Ronnie Overby

2

ฉันยอมรับใช้ฝั่งไคลเอ็นต์ แต่ดูเหมือนว่านั่นไม่ใช่คำตอบที่คุณต้องการฟัง

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

ฉันจะไม่เหงื่อออก


ฉันไม่มีปัญหากับฝั่งไคลเอ็นต์ขณะที่ฉันไปเส้นทางนั้นด้วยแอพ Windows แล้วเว็บแอพล่ะ ฉันไม่ค่อยพบว่าโซลูชัน JavaScript มีความยืดหยุ่นเพียงพอ ใช่มันใช้งานได้ตามที่ฉันพูดในแบบที่เรามี แต่มันเป็นฝันร้ายของ SQL แน่นอนฉันอยากรู้ว่ามีวิธีที่ดีกว่านี้ไหม
Sean Hanley

มีอยู่ในตัวควบคุม. NET ที่ใหม่กว่า (2.0 ขึ้นไป) หรือจะสร้างเองแล้วใช้กับ dataview ก็ได้ msdn.microsoft.com/en-us/library/hwf94875(VS.80).aspx
DS

2
ปัญหาของฉันคือหนึ่งในความสามารถในการปรับขนาดและประสิทธิภาพ การเรียงลำดับฝั่งไคลเอ็นต์หรือฝั่งเว็บเซิร์ฟเวอร์จำเป็นต้องโหลดข้อมูลทั้งหมดแทนที่จะเป็นเพียง 10 หรือ 15 รายการที่คุณจะแสดงในแต่ละหน้า สิ่งนี้มีค่าใช้จ่ายสูงมากในระยะยาวในขณะที่การจัดเรียงฐานข้อมูลไม่มีสิ่งนั้น
Sean Hanley

2

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

declare @o int;
set @o = -1;

declare @sql nvarchar(2000);
set @sql = N'select * from table order by ' + 
    cast(abs(@o) as varchar) + case when @o < 0 then ' desc' else ' asc' end + ';'

exec sp_executesql @sql

จากนั้นคุณต้องแน่ใจว่าตัวเลขนั้นอยู่ภายใน 1 ถึง # ของคอลัมน์ คุณยังสามารถขยายตัวนี้ไปยังรายการของหมายเลขคอลัมน์และแยกที่เป็นตารางของ ints โดยใช้ฟังก์ชั่นเช่นนี้ จากนั้นคุณจะสร้างคำสั่งตามข้อเช่นนั้น ...

declare @cols varchar(100);
set @cols = '1 -2 3 6';

declare @order_by varchar(200)

select @order_by = isnull(@order_by + ', ', '') + 
        cast(abs(number) as varchar) + 
        case when number < 0 then ' desc' else '' end
from dbo.iter_intlist_to_tbl(@cols) order by listpos

print @order_by

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


เราใช้ sp_executesql ในการสร้างแบบสอบถามการรายงานแบบไดนามิก มีประสิทธิภาพมาก ไม่สามารถสร้าง SQL จากแอปพลิเคชันได้ แต่จะมีการแทรกพารามิเตอร์ในที่ที่จำเป็นและดำเนินการตามปกติ
Josh Smeaton

2

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

สำหรับ Entity Framework คุณสามารถใช้กระบวนงานที่เก็บไว้เพื่อจัดการการค้นหาข้อความของคุณ หากคุณพบปัญหาการจัดเรียงเดียวกันวิธีแก้ปัญหาที่ฉันพบคือใช้ proc ที่จัดเก็บไว้สำหรับการค้นหาโดยส่งคืนเฉพาะชุดคีย์ id สำหรับการจับคู่ จากนั้นทำการสอบถามใหม่ (พร้อมการเรียงลำดับ) กับฐานข้อมูลโดยใช้รหัสในรายการ (มี) EF จัดการสิ่งนี้ได้ค่อนข้างดีแม้ว่าชุด ID จะค่อนข้างใหญ่ก็ตาม ใช่นี่เป็นการเดินทางไปกลับสองรอบ แต่จะช่วยให้คุณเก็บการเรียงลำดับของคุณไว้ในฐานข้อมูลได้เสมอซึ่งอาจมีความสำคัญในบางสถานการณ์และป้องกันไม่ให้คุณเขียนตรรกะของเรือบรรทุกในขั้นตอนการจัดเก็บ


1

วิธีจัดการการเรียงลำดับในสิ่งที่แสดงผลลัพธ์เช่นกริดรายงาน ฯลฯ แทนที่จะเป็น SQL

แก้ไข:

เพื่อชี้แจงสิ่งต่างๆเนื่องจากคำตอบนี้ได้รับการโหวตก่อนหน้านี้ฉันจะอธิบายรายละเอียดเล็กน้อย ...

คุณระบุว่าคุณรู้เกี่ยวกับการจัดเรียงฝั่งไคลเอ็นต์ แต่ต้องการหลีกเลี่ยงมัน นั่นคือสายของคุณแน่นอน

สิ่งที่ฉันต้องการจะชี้ให้เห็นก็คือการทำในฝั่งไคลเอ็นต์คุณสามารถดึงข้อมูลครั้งเดียวจากนั้นทำงานกับมันได้ตามที่คุณต้องการเมื่อเทียบกับการเดินทางหลายครั้งไปมาที่เซิร์ฟเวอร์ในแต่ละครั้ง การจัดเรียงจะเปลี่ยนไป

SQL Server ของคุณไม่ได้รับการเก็บภาษีในขณะนี้และยอดเยี่ยมมาก มันไม่ควรอย่างยิ่ง แต่เพียงเพราะมันไม่มากเกินไป แต่ก็ไม่ได้หมายความว่ามันจะเป็นแบบนั้นตลอดไป

หากคุณใช้ ASP.NET ที่ใหม่กว่าสำหรับการแสดงผลบนเว็บสิ่งเหล่านั้นจำนวนมากถูกอบเข้ามาแล้ว

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

ฉันไม่ใช่คนที่จะทำหน้าที่สนับสนุนในที่สุด แต่ให้คิดถึงสิ่งที่จะเกี่ยวข้องเนื่องจากมีการเพิ่ม / ลบคอลัมน์ภายในชุดข้อมูลต่างๆที่ใช้โดยขั้นตอนการจัดเก็บ (ต้องมีการปรับเปลี่ยนคำสั่ง CASE) หรือเมื่อจู่ๆแทนที่จะจัดเรียงตามสองคอลัมน์ผู้ใช้ตัดสินใจว่าต้องการสาม - ต้องการให้คุณอัปเดตกระบวนงานที่จัดเก็บไว้ทุกขั้นตอนซึ่งใช้วิธีนี้

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


นั่นน่าจะเป็นวิธีที่ถูกต้อง แต่ไม่ถือเป็น "วิธีที่ดีกว่า"
DS

เพราะอย่างนั้นฉันยังคงเขียนการเรียงลำดับของตัวเองทั้งใน C # หรือ JavaScript และดูเหมือนว่ามันควรจะง่ายและเร็วกว่าใน SQL ดังนั้นคำถามของฉัน ฉันพลาดอะไรบางอย่างที่ชัดเจนหรือเราติดอยู่กับการเขียนการเรียงลำดับที่กำหนดเองของเราเอง (ใน C # หรือ JavaScript) ทุกแอพที่เราทำงาน
Sean Hanley

3
เดี๋ยวก่อนแล้วชุดผลลัพธ์ที่มีแถวเป็นหมื่น ๆ ล่ะ? คุณไม่สามารถส่งคืนข้อมูลทั้งหมดนั้นให้กับไคลเอนต์ได้ คุณต้องทำเพจและเรียงลำดับบนฐานข้อมูล
Eric Z Beard

Yadyn เข้าใจ แต่เมื่อคุณมีตัวเรียงลำดับทั่วไปสำหรับกริดของคุณแล้วคุณก็จะใช้มันสำหรับสิ่งของทั้งหมดของคุณ
Kevin Fairchild

Eric จริง ... ในกรณีเช่นนั้นคุณจำเป็นต้องมีการจัดการเพิ่มเติมและบางทีมันอาจจะสมเหตุสมผลภายใน SQL ยังห่างไกลจากปัญหาที่ถูกและผิด ในบางกรณีมันจะสมเหตุสมผลสำหรับ SQL และบางกรณีบนไคลเอนต์
Kevin Fairchild

1

ขออภัยฉันไปปาร์ตี้ช้า แต่นี่เป็นอีกทางเลือกหนึ่งสำหรับผู้ที่ต้องการหลีกเลี่ยงไดนามิก SQL แต่ต้องการความยืดหยุ่นที่มีให้:

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

หากคุณมีเพียงไม่กี่รูปแบบคุณก็สามารถสร้าง procs ด้วยมือได้ แต่ถ้าคุณมีรูปแบบมากมายแทนที่จะต้องดูแลรักษาทั้งหมดคุณก็แค่ดูแลตัวสร้าง proc ของคุณแทนเพื่อให้มันสร้างขึ้นมาใหม่

เพื่อประโยชน์เพิ่มเติมคุณจะได้รับแผน SQL ที่ดีขึ้นเพื่อประสิทธิภาพที่ดีขึ้นด้วยวิธีนี้เช่นกัน


-1

โซลูชันนี้อาจใช้ได้เฉพาะใน. NET เท่านั้นฉันไม่รู้

ฉันดึงข้อมูลลงใน C # ด้วยลำดับการจัดเรียงเริ่มต้นในลำดับ SQL ตามส่วนวางข้อมูลนั้นใน DataView แคชในตัวแปรเซสชันและใช้เพื่อสร้างเพจ

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

คุณสามารถดู / รู้สึกว่ามันใช้งานได้ในการสาธิตแอป BugTracker.NET ของฉันที่http://ifdefined.com/btnet/bugs.aspx


หวาน! เครื่องติดตาม Bug.NET หิน!
digiguru

-7

คุณควรหลีกเลี่ยงการเรียงลำดับ SQL Server เว้นแต่ในกรณีที่จำเป็น ทำไมไม่จัดเรียงบนเซิร์ฟเวอร์แอปหรือฝั่งไคลเอ็นต์ นอกจากนี้. NET Generics ยังทำการเรียงลำดับที่ยอดเยี่ยม


6
เนื่องจากความสามารถในการขยายขนาด ไม่เป็นไรสำหรับแถวสองสามพัน แต่ฉันไม่ต้องการดึงลงมาเป็นหมื่นและเรียงลำดับนั้น หรือมากกว่า. แล้วเพจล่ะ? ฉันมักจะดึงเฉพาะสิ่งที่ต้องการมาแสดงเท่านั้น การเรียงลำดับแถวที่ 21-30 จาก 24056 ตามหลังข้อเท็จจริงจะไม่ถูกต้อง
Sean Hanley
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.