Reputation: 10248
I found some great sql code for dynamic sort & order but I am wondering if someone can help me re-jig it so that the CTE in the PROC below uses the dynamic sort/order. This code runs - but the output is not what I am after as the ORDER BY p.ProductId happens first in the CTE then the ORDER BY CASE statement only applies to the records 6 to 10
DECLARE @Skip int
DECLARE @Take int
DECLARE @OrderBy VARCHAR(50)
SET @Skip = 5;
SET @Take = 5;
SET @OrderBy = 'PriceAsc';
WITH ProductCT AS
(
SELECT ROW_NUMBER() OVER(ORDER BY p.ProductId) AS RowNum
, p.ProductId
FROM dbo.Product AS p
)
SELECT p.ProductId
,p.Title
,p.Price
FROM dbo.Product AS p
INNER JOIN ProductCT AS pct ON pct.ProductId = p.ProductId
WHERE pct.RowNum BETWEEN @Skip + 1 AND (@Skip + @Take)
ORDER BY
CASE
WHEN @OrderBy = 'TitleAsc' THEN (RANK() OVER (ORDER BY p.Title))
WHEN @OrderBy = 'TitleDesc' THEN (RANK() OVER (ORDER BY p.Title DESC))
WHEN @OrderBy = 'PriceAsc' THEN (RANK() OVER (ORDER BY p.Price))
WHEN @OrderBy = 'PriceDesc' THEN (RANK() OVER (ORDER BY p.Price DESC))
ELSE (RANK() OVER (ORDER BY p.Price))
END
Thanks in advance for any suggestions :-)
Upvotes: 4
Views: 3884
Reputation: 762
Rob's solutions somehow doesn't work for me, here is my modified version which worked fine.
SELECT
ROW_NUMBER() OVER (ORDER BY
CASE
WHEN @sortOrder = 'TitleAsc' THEN p.Title
WHEN @sortOrder = 'TitleDesc' THEN p.Title
WHEN @sortOrder = 'PatientId' THEN p.Title
WHEN @sortOrder = 'PriceAsc' THEN p.Title
WHEN @sortOrder = 'PriceDesc' THEN p.Title
END ASC) AS [RowNum],
.................
..................
Upvotes: 0
Reputation: 10248
I originally marked the answer from @Johan as correct because it worked, but I was a little unsure about the INNER JOIN also the overall complexity of this query.
I got chatting with a colleague of mine about the problem and he came up with this very tidy solution (thanks Tom!!) so I thought I would share it:
DECLARE @Skip int
DECLARE @Take int
DECLARE @OrderBy VARCHAR(50)
SET @Skip = 5;
SET @Take = 5;
SET @OrderBy = 'PriceAsc';
WITH ProductCT AS
(
SELECT
CASE
WHEN @OrderBy = 'TitleAsc' THEN ROW_NUMBER() OVER (ORDER BY p.Title)
WHEN @OrderBy = 'TitleDesc' THEN ROW_NUMBER() OVER (ORDER BY p.Title DESC)
WHEN @OrderBy = 'PriceAsc' THEN ROW_NUMBER() OVER (ORDER BY p.Price)
WHEN @OrderBy = 'PriceDesc' THEN ROW_NUMBER() OVER (ORDER BY p.Price DESC)
END AS RowNum
, p.ProductId
FROM dbo.Product AS p
)
SELECT p.ProductId
,p.Title
,p.Price
FROM dbo.Product AS p
INNER JOIN ProductCT AS pct ON pct.ProductId = p.ProductId
WHERE pct.RowNum BETWEEN @Skip + 1 AND (@Skip + @Take)
ORDER BY RowNum
Upvotes: 10
Reputation: 1192
Here is a solution that should work.
WITH ProductCT AS
(
SELECT ROW_NUMBER() OVER(ORDER BY p.Title) AS RowNum1
,ROW_NUMBER() OVER(ORDER BY p.Title DESC) AS RowNum2
,ROW_NUMBER() OVER(ORDER BY p.Price) AS RowNum3
,ROW_NUMBER() OVER(ORDER BY p.Price DESC) AS RowNum4
,p.ProductId
FROM dbo.Product AS p
)
SELECT p.ProductId
,p.Title
,p.Price
FROM dbo.Product AS p
INNER JOIN ProductCT AS pct
ON pct.ProductId = p.ProductId
AND ((@OrderBy = 'TitleAsc' AND pct.RowNum1 BETWEEN @Skip + 1 AND (@Skip + @Take))
OR (@OrderBy = 'TitleDesc' AND pct.RowNum2 BETWEEN @Skip + 1 AND (@Skip + @Take))
OR (@OrderBy = 'PriceAsc' AND pct.RowNum3 BETWEEN @Skip + 1 AND (@Skip + @Take))
OR (@OrderBy = 'PriceDesc' AND pct.RowNum4 BETWEEN @Skip + 1 AND (@Skip + @Take))
)
ORDER BY
CASE @OrderBy
WHEN 'TitleAsc' THEN RowNum1
WHEN 'TitleDesc' THEN RowNum2
WHEN 'PriceAsc' THEN RowNum3
WHEN 'PriceDesc' THEN RowNum4
ELSE RowNum3
END
I think the JOIN
could be written better but I dont have more time right now.
Upvotes: 0