conditional Order By SQL statement for tokio postgres in Rust [duplicate] - postgresql

How can i achieve dynamic order by column and sort direction in a postgresql function.
Here is what i have so far:
CREATE OR REPLACE FUNCTION get_urls_by_crawl_id(
p_account_id character varying(64),
p_crawl_id character varying(64),
p_sort_column character varying(30),
p_sort_direction character varying(30),
p_page integer,
p_total integer
)
RETURNS TABLE(id character varying(64), source_url text, http_status_code integer, ref_cnt integer) AS $BODY$
BEGIN
RETURN QUERY SELECT u.id, u.source_url, u.http_status_code, u.ref_cnt FROM url AS u
JOIN crawl AS c ON(u.crawl_id = c.id)
JOIN site AS s ON(c.site_id = s.id)
JOIN person AS p ON(s.person_id = p.id)
WHERE p.account_id = p_account_id AND u.crawl_id = p_crawl_id AND u.secured = 0
ORDER BY p_sort_column (CASE WHEN p_sort_direction = 'ASC' THEN ASC ELSE DESC END) LIMIT p_total OFFSET (p_page * p_total);
END;
$BODY$ LANGUAGE plpgsql;
the psql client returns this error:
ERROR: syntax error at or near "ASC"
LINE 16: ...t_column (CASE WHEN p_sort_direction = 'ASC' THEN ASC ELSE D...
I have tried multiple forms of the CASE statement but none seems to work.

Use two different order by keys:
ORDER BY (case when p_sort_direction = 'ASC' then p_sort_column end)
asc,
p_sort_column desc
LIMIT p_total OFFSET (p_page * p_total);
Note that you have another problem. p_sort_column is a string. You would need to use dynamic SQL to insert it into the code.
Alternatively, you can use a series of cases:
order by (case when p_sort_column = 'column1' and p_sort_direction = 'ASC' then column1 end) asc,
(case when p_sort_column = 'column1' and p_sort_direction = 'DESC' then column1 end) desc,
(case when p_sort_column = 'column2' and p_sort_direction = 'ASC' then column2 end) asc,
(case when p_sort_column = 'column2' and p_sort_direction = 'DESC' then column2 end) desc,
. . .

Related

Variables or Functions in Postrgres

I have the following code that gets the monthly resignation rate of people in a company
---2021
Select
c.id,
c.name as Company,
------January
round(cast( float8 (CASE
--employeesatendof2021
((Select count(e.id) from employee e
inner join person p on e.person = p.id
where e.company = c.id
and e.start_date Between '0001-01-01 00:00:00' and '2021-12-31 00:00:00'
and e.terminated_at is null
and p.is_support = false)
+
(Select count(e.id) from employee e
inner join person p on e.person = p.id
where e.company = c.id
and e.start_date is null
and e.terminated_at is null
and p.is_support = false))
WHEN 0 THEN null
Else
--eMPLOYEEsEPARATIONS2021
(Select count(e2.id) from employee e2
inner join person p2 on e2.person = p2.id
where e2.company = c.id
and e2.terminated_at at time zone l.timezone Between '2021-01-01 00:00:00' and '2021-1-31 24:00:00'
and p2.is_support = false)::numeric /
--employeesatendof2021
((Select count(e.id) from employee e
inner join person p on e.person = p.id
where e.company = c.id
and e.start_date Between '0001-01-01 00:00:00' and '2021-12-31 00:00:00'
and e.terminated_at is null
and p.is_support = false)
+
(Select count(e.id) from employee e
inner join person p on e.person = p.id
where e.company = c.id
and e.start_date is null
and e.terminated_at is null
and p.is_support = false))* 100
end)as numeric),2) as January_Resignation_Rate,
----February
round(cast( float8 (CASE
--employeesatendof2021
((Select count(e.id) from employee e
inner join person p on e.person = p.id
where e.company = c.id
and e.start_date Between '0001-01-01 00:00:00' and '2021-12-31 00:00:00'
and e.terminated_at is null
and p.is_support = false)
+
(Select count(e.id) from employee e
inner join person p on e.person = p.id
where e.company = c.id
and e.start_date is null
and e.terminated_at is null
and p.is_support = false))
--employeeSeaprtions2021
WHEN 0 THEN null
Else
--eMPLOYEEsEPARATIONS2021
(Select count(e2.id) from employee e2
inner join person p2 on e2.person = p2.id
where e2.company = c.id
and e2.terminated_at at time zone l.timezone Between '2021-02-01 00:00:00' and '2021-2-28 24:00:00'
and p2.is_support = false)::numeric /
--employeesatendof2021
((Select count(e.id) from employee e
inner join person p on e.person = p.id
where e.company = c.id
and e.start_date Between '0001-01-01 00:00:00' and '2021-12-31 00:00:00'
and e.terminated_at is null
and p.is_support = false)
+
(Select count(e.id) from employee e
inner join person p on e.person = p.id
where e.company = c.id
and e.start_date is null
and e.terminated_at is null
and p.is_support = false))* 100
end)as numeric),2) as February_Resignation_Rate,
CASE l.locale
WHEN 'en-AU' THEN 'Australia'
WHEN 'en-SA' THEN 'South Africa'
WHEN 'en-SG' THEN 'Singapore'
WHEN 'en-NZ' THEN 'New Zealand'
WHEN 'en-HK' THEN 'Hongkong'
WHEN 'en-UK' THEN 'United Kingdom'
end as locale
from company c
inner join location l on l.company = c.id and l.parent = 0
where l.locale = 'en-AU'
and c.id = 2
It works fine and does what it's supposed to do
But I've been using and hard coding this part of the code alot
--employeesatendof2021
((Select count(e.id) from employee e
inner join person p on e.person = p.id
where e.company = c.id
and e.start_date Between '0001-01-01 00:00:00' and '2021-12-31 00:00:00'
and e.terminated_at is null
and p.is_support = false)
+
(Select count(e.id) from employee e
inner join person p on e.person = p.id
where e.company = c.id
and e.start_date is null
and e.terminated_at is null
and p.is_support = false))
And I was wondering if there is a way to save this part of the script in a variable or function that I can use through out the script without hardcoding it?
Here conditional input is used for retrieving data. If any input parameter value is NULL or empty string then it'll not used for searching option. Prepare a query based on requirement and store it in variable. Then use RETURN QUERY EXECUTE variable_full_query for executing the query and return result. Always keep in mind that out parameter name and data type must be matched with select column name and data type. Use setof records means it returns multiple records.
-- Function: public.rpt_member_info(character varying, character varying, character varying, character varying, character varying)
DROP FUNCTION IF EXISTS public.rpt_member_info(character varying, character varying, character varying, character varying, character varying);
CREATE OR REPLACE FUNCTION public.rpt_member_info(
IN p_officeInfoId CHARACTER VARYING,
IN p_projectInfoId CHARACTER VARYING,
IN p_memberInfoId CHARACTER VARYING,
IN p_fromDate CHARACTER VARYING,
IN p_toDate CHARACTER VARYING,
OUT member_id BIGINT,
out office_info_id bigint,
out project_info_id bigint,
OUT member_no CHARACTER VARYING,
OUT member_name CHARACTER VARYING,
OUT membership_date TIMESTAMP WITHOUT TIME ZONE)
RETURNS SETOF record AS
$BODY$
-- declare local variables
DECLARE v_prepareQuery VARCHAR(21840) DEFAULT '';
v_officeInfo VARCHAR(150) DEFAULT '';
v_projectInfo VARCHAR(150) DEFAULT '';
v_memberInfo VARCHAR(150) DEFAULT '';
refcur refcursor default 'test';
BEGIN
/**************************History**************************/
-- Name : rpt_member_info
-- Created Date (dd/MM/yyyy): 20/01/2022
-- Created By : Rahul Biswas
-- Reason :
-- Execute : SELECT * FROM rpt_member_info('101', '1', '1', '2022-01-01', '2022-01-31');
/***********************************************************/
-- prepare variable data based on given input
IF(p_officeInfoId != '' AND p_officeInfoId != 'null' AND p_officeInfoId IS NOT NULL)
THEN
v_officeInfo = CONCAT(' AND mi.office_info_id = ', p_officeInfoId, CHR(10));
END IF;
IF(p_projectInfoId != '' AND p_projectInfoId != 'null' AND p_projectInfoId IS NOT NULL)
THEN
v_projectInfo = CONCAT(' AND mi.project_info_id = ', p_projectInfoId, CHR(10));
END IF;
IF(p_memberInfoId != '' AND p_memberInfoId != 'null' AND p_memberInfoId IS NOT NULL)
THEN
v_memberInfo = CONCAT(' AND mi.id = ', p_memberInfoId, CHR(10));
END IF;
-- prepare query
v_prepareQuery := CONCAT('SELECT mi.id member_id
, mi.office_info_id
, mi.project_info_id
, mi.member_no
, mi.member_name
, mi.membership_date
FROM member_info mi
WHERE 1 = 1', CHR(10)
, v_officeInfo
, v_projectInfo
, v_memberInfo
, 'AND mi.membership_date BETWEEN ', '''', p_fromDate, '''', ' AND ', '''', p_toDate, '''', ';');
RETURN QUERY EXECUTE v_prepareQuery;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
Execute the function with specific input value
SELECT * FROM rpt_member_info('101', '1', '1', '2022-01-01', '2022-01-31');
Execute the function when a param value is null or empty. This will return all values of a particular column
SELECT * FROM rpt_member_info('', 'null', NULL, '2022-01-01', '2022-01-31');
Please check this url https://dbfiddle.uk/?rdbms=postgres_11&fiddle=e0f26dfa36b4636f70bd5267dab29979
Also use variable in a query and return result where all parameter value is available and prepare query isn't stored in a variable.
-- Function: public.rpt_member_info(character varying, character varying, character varying, character varying, character varying)
DROP FUNCTION IF EXISTS public.rpt_member_info(character varying, character varying, character varying, character varying, character varying);
CREATE OR REPLACE FUNCTION public.rpt_member_info(
IN p_officeInfoId BIGINT,
IN p_projectInfoId BIGINT,
IN p_memberInfoId BIGINT,
IN p_fromDate TIMESTAMP WITHOUT TIME ZONE,
IN p_toDate TIMESTAMP WITHOUT TIME ZONE,
OUT member_id BIGINT,
out office_info_id bigint,
out project_info_id bigint,
OUT member_no CHARACTER VARYING,
OUT member_name CHARACTER VARYING,
OUT membership_date TIMESTAMP WITHOUT TIME ZONE)
RETURNS SETOF record AS
$BODY$
-- declare local variables
DECLARE v_prepareQuery VARCHAR(21840) DEFAULT '';
v_officeInfo VARCHAR(150) DEFAULT '';
v_projectInfo VARCHAR(150) DEFAULT '';
v_memberInfo VARCHAR(150) DEFAULT '';
refcur refcursor default 'test';
BEGIN
/**************************History**************************/
-- Name : rpt_member_info
-- Created Date (dd/MM/yyyy): 20/01/2022
-- Created By : Rahul Biswas
-- Reason :
-- Execute : SELECT * FROM rpt_member_info(101, 1, 1, '2022-01-01', '2022-01-31');
/***********************************************************/
-- execute query
RETURN QUERY SELECT mi.id member_id
, mi.office_info_id
, mi.project_info_id
, mi.member_no
, mi.member_name
, mi.membership_date
FROM member_info mi
WHERE mi.office_info_id = p_officeInfoId
AND mi.project_info_id = p_projectInfoId
AND mi.id = p_memberInfoId
AND mi.membership_date BETWEEN p_fromDate AND p_toDate;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
Execute the function
SELECT * FROM rpt_member_info(101, 1, 1, '2022-01-01', '2022-01-31');
Please check this url https://dbfiddle.uk/?rdbms=postgres_11&fiddle=7c8ed1d02f51f5df4e263cc36a2d50e8

Can I insert a dynamic number of rows into a table using values from the table?

I want to insert a dynamic number of rows into a table, based on information in that table.
I can do it using the code below, but I'm wondering if there's a way to avoid the loop.
The commented out section was my best attempt at what I was trying to do, but it gave me an error of:
"The reference to column "iCount" is not allowed in an argument to a TOP, OFFSET, or FETCH clause. Only references to columns at an outer scope or standalone expressions and subqueries are allowed here."
DECLARE #TableX TABLE (
TDate DATE
, TType INT
, Fruit NVARCHAR(20)
, Vegetable NVARCHAR(20)
, Meat NVARCHAR(20)
, Bread NVARCHAR(20)
)
INSERT INTO #TableX VALUES
('2016-11-10',1,'Apple','Artichoke',NULL,NULL)
, ('2016-11-10',1,'Banana','Beet',NULL,NULL)
, ('2016-11-10',1,'Canteloupe','Cauliflower',NULL,NULL)
, ('2016-11-10',1,'Durian','Daikon',NULL,NULL)
, ('2016-11-10',2,NULL,NULL,'Rabbit','Rye')
, ('2016-11-10',2,NULL,NULL,'Sausage','Sourdough')
, ('2016-11-11',1,'Elderberry','Eggplant',NULL,NULL)
, ('2016-11-11',2,NULL,NULL,'Turkey','Tortilla')
, ('2016-11-11',2,NULL,NULL,'Venison','Vienna')
SELECT * FROM #TableX
DECLARE #BlankRow TABLE (
ID INT IDENTITY
, TDate DATE
, TType INT
, iCount INT
)
DECLARE #Counter1 INT = 0
, #RowCount INT
; WITH BR1
AS (
SELECT TDate, TType, COUNT(*) AS iCount
FROM #TableX
WHERE TType = 1
GROUP BY TDate, TType
)
, BR2
AS (
SELECT TDate, TType, COUNT(*) AS iCount
FROM #TableX
WHERE TType = 2
GROUP BY TDate, TType
)
INSERT INTO #BlankRow
SELECT ISNULL(BR1.TDate, BR2.TDate) AS TDate,
CASE WHEN ISNULL(BR1.iCount,0) < ISNULL(BR2.iCount,0) THEN 1 ELSE 2 END AS TType,
ABS(ISNULL(BR1.iCount,0) - ISNULL(BR2.iCount,0)) AS iCount
FROM BR1
FULL JOIN BR2
ON BR1.TDate = BR2.TDate
WHILE #Counter1 < (SELECT MAX(ID) FROM #BlankRow)
BEGIN
SET #Counter1 += 1
SET #RowCount = (SELECT iCount FROM #BlankRow WHERE ID = #Counter1)
INSERT INTO #TableX
SELECT TOP (#RowCount) tx.TDate, br.TType, NULL, NULL, NULL, NULL
FROM #TableX tx
LEFT JOIN #BlankRow br
ON tx.TDate = br.TDate
WHERE br.ID = #Counter1
END
/*INSERT INTO #TableX
SELECT TOP (tx.iCount) tx.TDate, br.TType, NULL, NULL, NULL, NULL
FROM #TableX tx
JOIN #BlankRow br
ON tx.TDate = br.TDate*/
SELECT *
FROM #TableX
ORDER BY TDate, TType,
ISNULL(Fruit,REPLICATE(CHAR(255),20)),
ISNULL(Vegetable,REPLICATE(CHAR(255),20)),
ISNULL(Meat,REPLICATE(CHAR(255),20)),
ISNULL(Bread,REPLICATE(CHAR(255),20))
The data is silly, I know, but my end goal is to have two different Tablix's in ReportBuilder that end up with the same number of rows so the headers of my groups show up at the same place on the page.
Something like this:
declare #TableX table(TDate date
,TType int
,Fruit nvarchar(20)
,Vegetable nvarchar(20)
,Meat nvarchar(20)
,Bread nvarchar(20)
);
insert into #TableX values
('2016-11-10',1,'Apple','Artichoke',NULL,NULL)
,('2016-11-10',1,'Banana','Beet',NULL,NULL)
,('2016-11-10',1,'Canteloupe','Cauliflower',NULL,NULL)
,('2016-11-10',1,'Durian','Daikon',NULL,NULL)
,('2016-11-10',2,NULL,NULL,'Rabbit','Rye')
,('2016-11-10',2,NULL,NULL,'Sausage','Sourdough')
,('2016-11-11',1,'Elderberry','Eggplant',NULL,NULL)
,('2016-11-11',2,NULL,NULL,'Turkey','Tortilla')
,('2016-11-11',2,NULL,NULL,'Venison','Vienna');
with DataRN as
(
select *
,row_number() over (partition by TDate, TType order by TDate) rn
from #TableX
)
,RowsRN as
(
select tt.TDate
,tt.TType
,td.rn
from (select distinct TDate, TType
from #TableX
) tt
full join (select distinct t1.TDate
,row_number() over (partition by t1.TDate, t1.TType order by t1.TDate) rn
from #TableX t1
) td
on(tt.TDate = td.TDate)
)
select r.TDate
,r.TType
,d.Fruit
,d.Vegetable
,d.Meat
,d.Bread
from DataRN d
full join RowsRN r
on(d.TDate = r.TDate
and d.TType = r.TType
and d.rn = r.rn
)
order by r.TDate
,r.TType
,isnull(d.Fruit,REPLICATE(CHAR(255),20))
,isnull(d.Vegetable,REPLICATE(CHAR(255),20))
,isnull(d.Meat,REPLICATE(CHAR(255),20))
,isnull(d.Bread,REPLICATE(CHAR(255),20))
In response to your comment, here is how you would use another cte to generate the full list of dates that you would need, if you havn't got a Dates reference table already (These are tremendously useful):
declare #MinDate date = (select min(TDate) from #TableX);
declare #MaxDate date = (select max(TDate) from #TableX);
with Dates as
(
select #MinDate as DateValue
union all
select dateadd(d,1,DateValue)
from Dates
where DateValue < #MaxDate
)
select DateValue
from Dates
option (maxrecursion 0);

Using parameters of Stored Procedure with Join's "ON" area

I have parameters like these
declare #Phl1_descr varchar(50)
SET #Phl1_descr = 'Greece'
declare #Phl2_descr varchar(50)
SET #Phl2_descr = 'Coffee & Beverages'
I want to join two tables with the above parameters (if they are not null), so I tried to do something like below in the "ON" keyword of my JOIN
ON
(CASE WHEN LEN(#Phl1_descr) > 0 THEN A.Phl1_descr ELSE B.Phl1_descr END) = B.Phl1_descr AND
(CASE WHEN LEN(#Phl2_descr) > 0 THEN A.Phl2_descr ELSE B.Phl2_descr END) = B.Phl2_descr
However if I send one of the parameters like as '', it doesn't work. Any simpler idea?
Is it posible to use simpler solution? Like:
IF #Phl1_descr IS NOT NULL AND #Phl2_descr IS NOT NULL
BEGIN
SELECT *
FROM Table1 as A
LEFT JOIN Table2 as B on A.Phl1_descr=B.Phl1_descr and A.Phl2_descr=B.Phl2_descr
END
ELSE IF #Phl1_descr IS NOT NULL AND #Phl2_descr IS NULL
BEGIN
SELECT *
FROM Table1 as A
LEFT JOIN Table2 as B on A.Phl1_descr=B.Phl1_descr
END
ELSE IF #Phl1_descr IS NULL AND #Phl2_descr IS NOT NULL
BEGIN
SELECT *
FROM Table1 as A
LEFT JOIN Table2 as B on A.Phl2_descr=B.Phl2_descr
END
So you will get a simpler execution plans and simpler logic.
You can also use ... CASE WHEN #Phl1_descr IS NULL THEN ... to check NULL values
Interesting but
B.Phl1_descr = B.Phl1_descr
not working but
ISNULL(B.Phl1_descr,'-1') = ISNULL(B.Phl1_descr,'-1')
works,
So just a simple change in the below code work it out
(CASE WHEN LEN(#Phl1_descr) > 1 THEN A.Phl1_descr ELSE ISNULL(B.Phl1_descr,'-1') END) = ISNULL(B.Phl1_descr,'-1') AND
(CASE WHEN LEN(#Phl2_descr) > 1 THEN A.Phl2_descr ELSE ISNULL(B.Phl2_descr,'-1') END) = ISNULL(B.Phl2_descr,'-1') AND

SQL Server 2000: select into case when in order by clause

I am trying to select rows into a temporary table with a CASE statement in the ORDER BY clause but records are not being sorted on insert.
Declare #orderby varchar(10) , #direction varchar(10)
set #orderby = 'col1'
set #direction = 'desc'
select identity (int) as autoid, *
into #temp
from table
order by case when #direction = 'desc' and #orderby = 'co1' then col1 end desc
declare #startrow int
declare #maxrows int
set #starrow = 19
set #maxrow = 30
set rowcount #maxrows
select * from #temp
where autoid > #startrow
Worst case - you'll just have to use two separate SQL queries to achieve your goal:
if #direction = 'desc'
select identity (int) as autoid, *
into #temp
from table
order by col1 desc
if #direction = 'asc'
select identity (int) as autoid, *
into #temp
from table
order by col1 asc
You'll need to use multiple sort conditions in your order by clause to handle this properly. The problem with this approach is that the performance will be bad when you have a lot of rows in the table because of that nasty sort operation.
Instead, you may be better off using dynamic SQL (as someone else suggested).
Declare #orderby varchar(100) , #direction varchar(10)
set #orderby = 'col1'
set #direction = 'desc'
select identity (int) as autoid, *
into #temp
from table
order by case when #direction = 'desc' and #orderby = 'col1' then col1 end desc,
case when #direction = 'asc' and #orderby = 'col1' then col1 end,
case when #direction = 'desc' and #orderby = 'col2' then col2 end desc,
case when #direction = 'asc' and #orderby = 'col2' then col2 end,
case when #direction = 'desc' and #orderby = 'col3' then col3 end desc,
case when #direction = 'asc' and #orderby = 'col3' then col3 end,
case when #direction = 'desc' and #orderby = 'col4' then col4 end desc,
case when #direction = 'asc' and #orderby = 'col4' then col4 end,
case when #direction = 'desc' and #orderby = 'col5' then col5 end desc,
case when #direction = 'asc' and #orderby = 'col5' then col5 end
You can achieve this not using #temp tables insted use normal table temp. Later when you are done with your process you can drop it at the end.
declare #dir varchar(10)='desc'
DECLARE #str varchar(1000)
SET #str='select identity (int) as autoid,
* into temp from cust1 order by TransactionType '+#dir
exec(#str)
select * from temp

T-SQL Paging Sorting & Filtering - Filtering not Working

T-SQL Paging Sorting & Filtering
I have been working on a T-SQL stored procedure for a number of hours now that will enable me to retrieve a paged set of articles that are sorted in ASC or DESC order based on a specified column.
I am now working on getting the stored procedure to filter based on the first character of the 'Title' field and have added the lines:
#StartAlpha nvarchar(1) = null
and
WHERE ((#StartAlpha IS NULL) OR (Title Like #StartAlpha + '%'))
see below.
The stored procedure no longer returns any results. And I don't really know why.
Can anyone please help?
Regards
Walter
USE [ABC]
GO
/****** Object: StoredProcedure [dbo].[Get_MyArticles_Paged] Script Date: 08/07/2011 20:41:28 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[Get_MyArticles_Paged]
/*Paging Total For Output*/
#Row_Count BIGINT OUT,
/*Paging Inputs*/
#Page_Size INT = 10,
#Page_Number INT = 1,
#Sort_Column VARCHAR(100), /* ('articleid','createdate','title','subject') */
#Sort_Direction VARCHAR(4), /* ('ASC','DESC') */
#StartAlpha nvarchar(1) = null
AS
BEGIN
print #StartAlpha
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
/*========================================================================
Declare local variables
========================================================================*/
DECLARE #FirstRecord int
DECLARE #LastRecord int
-- create a temporary space for paged result set
DECLARE #PagedResults AS TABLE (
[ArticleID] INT,
[CreateDate] SMALLDATETIME,
[Title] VARCHAR(200),
[Subject] VARCHAR(500),
[Row_Number] BIGINT,
[Row_Count] BIGINT
);
/*========================
Normalize Paging Parameters
==========================*/
--Fix invalid input for Page Size
SET #Page_Size = CASE
WHEN #Page_Size IS NULL THEN 10
WHEN #Page_Size < 1 THEN 10
ELSE #Page_Size
END;
--Fix invalid input for Page Number
SET #Page_Number = CASE
WHEN #Page_Number IS NULL THEN 1
WHEN #Page_Number < 1 THEN 1
ELSE #Page_Number
END;
--starting record to use.
SET #FirstRecord = ((#Page_Number - 1) * #Page_Size) + 1
--last record to use.
SET #LastRecord = #FirstRecord + #Page_Size - 1
--ensure sort column is valid in the list
SET #Sort_Column = CASE
WHEN LOWER(#Sort_Column) IN ('articleid','createdate','title','subject')
THEN LOWER(#Sort_Column)
ELSE
'title' --default
END
--ensure sort direction is ASC or DESC
SET #Sort_Direction = CASE
WHEN LEFT(UPPER(COALESCE(#Sort_Direction, '')) + ' ', 4) = 'DESC'
THEN 'DESC' --explicit descending
WHEN #Sort_Column = 'created' AND LEFT(UPPER(COALESCE(#Sort_Direction,'')) + ' ', 3) <> 'ASC' THEN
'DESC' --default for created date
ELSE 'ASC' --default otherwise
END;
/*============
Prepare Results
==============*/
WITH [MyTempArea] AS (
SELECT TOP (#LastRecord)
[ArticleID],
[CreateDate],
[Title],
[Subject],
ROW_NUMBER() OVER (
ORDER BY
CASE WHEN(#Sort_Direction = 'ASC') THEN CASE WHEN #Sort_Column='articleid' THEN [articleid] END END ASC,
CASE WHEN(#Sort_Direction = 'ASC') THEN CASE WHEN #Sort_Column='createdate' THEN [createdate] END END ASC,
CASE WHEN(#Sort_Direction = 'ASC') THEN CASE WHEN #Sort_Column='title' THEN [title] END END ASC,
CASE WHEN(#Sort_Direction = 'ASC') THEN CASE WHEN #Sort_Column='subject' THEN [subject] END END ASC,
CASE WHEN(#Sort_Direction = 'DESC') THEN CASE WHEN #Sort_Column='articleid' THEN [articleid] END END DESC,
CASE WHEN(#Sort_Direction = 'DESC') THEN CASE WHEN #Sort_Column='createdate' THEN [createdate] END END DESC,
CASE WHEN(#Sort_Direction = 'DESC') THEN CASE WHEN #Sort_Column='title' THEN [title] END END DESC,
CASE WHEN(#Sort_Direction = 'DESC') THEN CASE WHEN #Sort_Column='subject' THEN [subject] END END DESC
) AS [Row_Number],
COUNT(*) OVER () AS [Row_Count]
FROM Articles
WHERE ((#StartAlpha IS NULL) OR (Title Like #StartAlpha + '%'))
)
INSERT INTO #PagedResults
SELECT * FROM [MyTempArea] WHERE [Row_Number] >= #FirstRecord;
/*===========
Return Results
=============*/
-- #Row_Count output param
SELECT #Row_Count = COALESCE(MAX(Row_Count), 0) FROM #PagedResults;
-- Paged results set to return
SELECT [ArticleID],[CreateDate],[Title],[Subject]
FROM #PagedResults
ORDER BY [Row_Number];
END
Thanks to everyone that made helpful suggestions.
I completely refactored the stored procedure and it now works. See below.
I'm not entirely sure why the original Stored Procedure didn't work and why this version does, but I thought I would share with the forum.
Thanks again.
Walter.
ALTER PROCEDURE [dbo].[Account_ContactGetData]
#CurrentPage int = null,
#PageSize int = null,
#SortColumn nvarchar(max) = null,
#SortDirection varchar(5),
#StartAlpha nvarchar(1) = null
WITH EXECUTE AS CALLER
AS
BEGIN
SET NOCOUNT ON;
DECLARE #FirstRecord int;
DECLARE #LastRecord int;
--starting record to use.
SET #FirstRecord = ((#CurrentPage - 1) * #PageSize) + 1;
--last record to use.
SET #LastRecord = #FirstRecord + #PageSize - 1;
with ContactCTE as
(
SELECT [ContactID], [DisplayName], [FirstName], [MiddleName], [LastName],
(ROW_NUMBER() OVER (Order By
CASE WHEN #SortColumn='ContactID' AND #SortDirection='DESC' THEN ContactID END DESC,
CASE WHEN #SortColumn='ContactID' AND #SortDirection='ASC' THEN ContactID END ASC,
CASE WHEN #SortColumn='DisplayName' AND #SortDirection='DESC' THEN DisplayName END DESC,
CASE WHEN #SortColumn='DisplayName' AND #SortDirection='ASC' THEN DisplayName END ASC,
CASE WHEN #SortColumn='FirstName' AND #SortDirection='DESC' THEN FirstName END DESC,
CASE WHEN #SortColumn='FirstName' AND #SortDirection='ASC' THEN FirstName END ASC,
CASE WHEN #SortColumn='MiddleName' AND #SortDirection='DESC' THEN MiddleName END DESC,
CASE WHEN #SortColumn='MiddleName' AND #SortDirection='ASC' THEN MiddleName END ASC,
CASE WHEN #SortColumn='LastName' AND #SortDirection='DESC' THEN LastName END DESC,
CASE WHEN #SortColumn='LastName' AND #SortDirection='ASC' THEN LastName END ASC
)) AS Row
FROM Contact
WHERE
((#StartAlpha is NULL) OR (LastName Like #StartAlpha+ '%'))
)
SELECT [ContactID], [DisplayName], [FirstName], [MiddleName], [LastName]
FROM ContactCTE
WHERE Row BETWEEN #FirstRecord AND #LastRecord
END
Based on those requirements alone, this is what I would do:
WHERE ((#StartAlpha IS NULL) OR (LEFT(Title, 1) = #StartAlpha))
What do you get when you run just this part? (Please also state which values you are using in your parameters)
WITH [MyTempArea] AS (
SELECT TOP (#LastRecord)
[ArticleID],
[CreateDate],
[Title],
[Subject],
ROW_NUMBER() OVER (
ORDER BY
CASE WHEN(#Sort_Direction = 'ASC') THEN CASE WHEN #Sort_Column='articleid' THEN [articleid] END END ASC,
CASE WHEN(#Sort_Direction = 'ASC') THEN CASE WHEN #Sort_Column='createdate' THEN [createdate] END END ASC,
CASE WHEN(#Sort_Direction = 'ASC') THEN CASE WHEN #Sort_Column='title' THEN [title] END END ASC,
CASE WHEN(#Sort_Direction = 'ASC') THEN CASE WHEN #Sort_Column='subject' THEN [subject] END END ASC,
CASE WHEN(#Sort_Direction = 'DESC') THEN CASE WHEN #Sort_Column='articleid' THEN [articleid] END END DESC,
CASE WHEN(#Sort_Direction = 'DESC') THEN CASE WHEN #Sort_Column='createdate' THEN [createdate] END END DESC,
CASE WHEN(#Sort_Direction = 'DESC') THEN CASE WHEN #Sort_Column='title' THEN [title] END END DESC,
CASE WHEN(#Sort_Direction = 'DESC') THEN CASE WHEN #Sort_Column='subject' THEN [subject] END END DESC
) AS [Row_Number],
COUNT(*) OVER () AS [Row_Count]
FROM Articles
WHERE ((#StartAlpha IS NULL) OR (Title Like #StartAlpha + '%'))
)
SELECT * FROM [MyTempArea]
#Andreas LEFT(Title, 1) syntax would perform better than the like comparison... but using the like, this should work:
WHERE (Title Like isnull(#StartAlpha, '') + '%')
(The combination of working with nulls that OR makes me edgy.)