Це питання, про яке я витрачав години на дослідження. Мені здається, це те, що повинно було вирішуватись сучасними рішеннями RDBMS, але поки я не знайшов нічого, що насправді стосується того, що я вважаю надзвичайно поширеною потребою в будь-якому додатку для Інтернету чи Windows із базою даних бази даних.
Я кажу про динамічне сортування. У моєму фантастичному світі це повинно бути таким же простим, як щось на зразок:
ORDER BY @sortCol1, @sortCol2
Це канонічний приклад, який дають розробники SQL і зберігаються процедури на всіх форумах в Інтернеті. "Чому це неможливо?" запитують вони. Незмінно хтось з часом приходить разом з ними ознайомитись зі сформованим характером збережених процедур, планами виконання в цілому та всілякими іншими причинами, чому неможливо ввести параметр безпосередньо в ORDER BY
пункт.
Я знаю, що дехто з вас вже думає: "Давайте, тоді клієнт робити сортування". Природно, це вивантажує роботу з вашої бази даних. У нашому випадку сервери баз даних навіть не порушують потужність 99% часу, і вони навіть не є багатоядерними, або будь-яке інше безліч вдосконалень архітектури системи, які відбуваються кожні 6 місяців. Тільки з цієї причини не матиме проблеми з сортуванням наших баз даних. Крім того, бази даних дужедобре сортується. Вони оптимізовані для цього і мали роки, щоб правильно це зробити, мова для його роботи неймовірно гнучка, інтуїтивна та проста, і перш за все будь-який початківець письменник SQL знає, як це зробити, і ще важливіше, що вони знають, як це редагувати, вносити зміни, робити технічне обслуговування тощо. Коли ваші бази даних далекі від оподаткування, і ви просто хочете спростити (і скоротити!) час розробки, це здається очевидним вибором.
Тоді є веб-випуск. Я розігрувався з JavaScript, який буде робити сортування HTML-таблиць на стороні клієнта, але вони неминуче недостатньо гнучкі для моїх потреб, і, знову ж таки, оскільки мої бази даних не надмірно оподатковуються і можуть сортувати дуже легко, я важко виправдати час, який знадобиться, щоб переписати або прокрутити власний сортувальник JavaScript. Те саме стосується сортування на стороні сервера, хоча це, мабуть, набагато більше переваги над JavaScript. Мені не дуже подобається накладні витрати на DataSets, тому позов мене.
Але це повертає те, що це неможливо - точніше, не просто. З попередніми системами я зробив неймовірно злому способу отримання динамічного сортування. Це було не красиво, не інтуїтивно, просто та гнучко, і початківець SQL-програвач був би втрачений за лічені секунди. Вже зараз це виглядає не стільки «рішенням», скільки «ускладненням».
Наступні приклади не мають на меті розкривати будь-які найкращі практики чи гарний стиль кодування чи що-небудь, а також не свідчать про мої здібності як програміста T-SQL. Вони є такими, якими вони є, і я повністю визнаю, що вони збивають з пантелику, поганою формою і просто очевидним злом.
Ми передаємо ціле значення як параметр у збережену процедуру (назвемо параметр просто "сортування") і з цього визначимо купу інших змінних. Наприклад ... скажімо, сортування дорівнює 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, щоб визначити інші стовпці, я міг би по-справжньому отримати творчість за допомогою стовпців, щоб сортувати на основі значення "сортувати" ... щоб використовувати його, зазвичай це виглядає як наступне неймовірно безладний пункт:
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
Очевидно, що це дуже позбавлений приклад. Справжній матеріал, оскільки у нас зазвичай є чотири або п’ять стовпців для підтримки сортування, кожен з яких можливий вторинний або навіть третій стовпчик для сортування на додаток до цього (наприклад, дату спадання, потім відсортовану вдруге за прізвищем за зростанням) та кожну підтримуючу бі- спрямоване сортування, яке ефективно подвоює кількість випадків. Так ... вона стає волохатою дійсно швидко.
Ідея полягає в тому, що можна «легко» змінити випадки сортування таким чином, щоб транспортний засіб було відсортовано перед тим, як зберігати час… але псевдо-гнучкість, принаймні в цьому простому прикладі, справді закінчується. По суті, кожен випадок, який не виконує тест (оскільки наш метод сортування не застосовується до цього часу), має значення NULL. Таким чином, ви закінчуєте пропозицію, яка функціонує так:
ORDER BY NULL DESC, NULL, [storagedatetime] DESC, blah blah
Ви отримуєте ідею. Це працює тому, що SQL Server ефективно ігнорує нульові значення в порядку за допомогою пунктів. Це надзвичайно важко підтримувати, оскільки, напевно, може бачити кожен, хто має будь-які базові знання SQL. Якщо я загубив когось із вас, не відчувайте себе погано. Нам знадобилося багато часу, щоб ми працювали, і ми все ще плутаємося, намагаючись редагувати його або створювати нові, як це. На щастя, його не потрібно часто змінювати, інакше це швидко стане «не вартим клопоту».
Тим НЕ менше , він зробив роботу.
Моє запитання тоді: чи є кращий спосіб?
Я в порядку з іншими рішеннями, ніж ті, що зберігаються, оскільки я розумію, що це може бути не так. Переважно, я хотів би знати, чи може хтось зробити це краще в рамках Збереженої процедури, але якщо ні, як ви все обробляєте, дозволяючи користувачеві динамічно сортувати таблиці даних (теж двонаправлені) за допомогою ASP.NET?
І дякую за те, що ви прочитали (або принаймні скумпували) таке довге запитання!
PS: Будьте раді, що я не показав свого прикладу збереженої процедури, яка підтримує динамічне сортування, динамічне фільтрування / пошук тексту за стовпцями, розбиття сторінок за допомогою ROWNUMBER () НАД і І спробувати ... спіймати за допомогою трансляції транзакцій на помилках ... "розмір бегемота" навіть не починає їх описувати.
Оновлення:
- Я хотів би уникнути динамічного SQL . Розбиття рядка разом і запуск EXEC на ньому перешкоджає значній мірі мати збережену процедуру в першу чергу. Іноді я замислююся, хоч чи не варто цього робити, хоча б у цих особливих динамічних випадках сортування. Тим не менш, я завжди відчуваю себе брудним, коли роблю такі динамічні рядки SQL - як, як і раніше, живу в класичному світі ASP.
- Дуже багато причин, які ми хочемо, щоб збережені процедури в першу чергу були в безпеці . Я не можу телефонувати з питань безпеки, лише пропоную рішення. За допомогою SQL Server 2005 ми можемо встановлювати дозволи (на основі кожного користувача, якщо це необхідно) на рівні схеми для окремих збережених процедур, а потім заперечувати будь-які запити до таблиць безпосередньо. Критикувати плюси та мінуси такого підходу можливо для іншого питання, але знову це не моє рішення. Я просто мавпа з провідним кодом. :)