У меня есть следующий дб и запрос. Запрос берет два параметра: столбец вида и направление. Однако я должен добавить, пользовательская сортировка к запросу (на основе Фуджи должен прибыть первая и Праздничная секунда, и т.д.). Эта часть также работает, но она создает дублированный код в моем запросе. Из-за этого я - вполне уверенные люди, не позволит мне регистрировать это. Таким образом, мой вопрос: существует ли способ не копировать Оператор выбора?
CREATE TABLE Fruits (
[type] nvarchar(250),
[variety] nvarchar(250),
[price] money
)
GO
INSERT INTO Fruits VALUES ('Apple', 'Gala', 2.79)
INSERT INTO Fruits VALUES ('Apple', 'Fuji', 0.24)
INSERT INTO Fruits VALUES ('Apple', 'Limbertwig', 2.87)
INSERT INTO Fruits VALUES ('Orange', 'Valencia', 3.59)
INSERT INTO Fruits VALUES ('Pear', 'Bradford', 6.05)
DECLARE @sortColumnName nvarchar(MAX) = 'Variety'
DECLARE @sortDirection nvarchar(MAX) = 'ASC'
SELECT ROW_NUMBER() OVER (ORDER BY
CASE WHEN @sortColumnName = 'Variety' AND @sortDirection = 'ASC'
THEN
CASE f.Variety
WHEN 'Fuji' THEN 1
WHEN 'Gala' THEN 2
ELSE 3
END
END ASC,
CASE WHEN @sortColumnName = 'Variety' AND @sortDirection = 'DESC'
THEN
CASE f.Variety
WHEN 'Fuji' THEN 1
WHEN 'Gala' THEN 2
ELSE 3
END
END DESC), *
FROM Fruits f
Вы можете умножить ключ сортировки на +1 или -1 в зависимости от того, запрашивается ASC или DESC:
SELECT ROW_NUMBER() OVER (ORDER BY
CASE WHEN @sortColumnName = 'Variety'
THEN
(CASE f.Variety
WHEN 'Fuji' THEN 1
WHEN 'Gala' THEN 2
ELSE 3
END)
END
* (CASE WHEN @sortDirection = 'ASC' THEN 1 ELSE -1 END)), *
FROM Fruits f
Почему бы не иметь еще одну таблицу для сопоставимого значения, объединить по столбцу сорта и сортировать по сопоставимому значению.
Например,
INSERT INTO FruitSort VALUES ('Gala', 2)
INSERT INTO FruitSort VALUES ('Fuji', 1)
SELECT ROW_NUMBER() OVER (ORDER BY FruitSort.sortvalue)
FROM Fruits f
JOIN FruitSort
ON FruitSort.variety == Fruits.variety
Разве это не поможет и в этом случае, хотя и будет немного больше соответствовать базе данных?
Я не очень практичен, поэтому синтаксис, вероятно, довольно сломан. Однако мне очень не нравится концепция операторов 'CASE' в SQL.
Поскольку вы используете SQL 2008, вы можете использовать CTE:
;WITH CTE AS
(
SELECT
CASE WHEN @sortColumnName = 'Variety' THEN
CASE f.Variety
WHEN 'Fuji' THEN 1
WHEN 'Gala' THEN 2
ELSE 3
END
END AS sort_column,
*
FROM
Fruits F
)
SELECT
ROW_NUMBER() OVER (
ORDER BY
CASE WHEN @sortDirection = 'DESC' THEN sort_column ELSE 0 END DESC,
CASE WHEN @sortDirection = 'ASC' THEN sort_column ELSE 0 END ASC),
type,
variety,
price
FROM
CTE
Это не так гладко, как решение *-1 для этой конкретной проблемы, но его можно адаптировать для других ситуаций, когда вы хотите избежать дублирования кода.