How to use WITH result table multiple times? - sql

DECLARE #count INT;
WITH CTE AS
(SELECT...)
SELECT #count = COUNT(ID) FROM CTE;
SELECT * FROM CTE
Can I use CTE table after first expression SELECT #count = COUNT(ID) FROM CTE? I get error Invalid object name 'CTE'.
I'm using SQL Server 2008.
Thanks

You can't, really; the CTE only exists for the scope of a single statement. However in this case you could do this:
DECLARE #count INT;
WITH CTE AS (SELECT...)
SELECT * FROM CTE;
SELECT #count = ##ROWCOUNT;
If you need the count as part of the resultset, then you can just say:
WITH CTE AS (SELECT...)
SELECT *, COUNT(*) OVER() FROM CTE;
If you need the count for other reasons, please describe them.

You could use a table variable and use it everywhere.
DECLARE #count INT;
DECLARE #CTE AS TABLE (<<columns>>)
INSERT INTO #CTE (<<columns>>)
SELECT ....
WITH CTE AS
(SELECT * FROM #CTE)
SELECT #count = COUNT(ID) FROM CTE;
SELECT * FROM #CTE

Related

SQL Server run SELECT for each in list

I won't be surprised if SQL just doesn't work this way at all, but:
If we run two SELECT statements in a query, we get a split "Results" pane. I'm wondering if I can add variables to a list, and then have the number of result pane splits match the length of that list.
If I were to mix languages:
id_list = [26275, 54374, 84567]
for i in id_list:
SELECT * FROM table WHERE id = i
I'm just trying to easily compare results of a query while keeping distinct groups, with a changing number of variables. Since loops never seem to be the answer in SQL, I'd be just as happy inserting something like a blank line or horizontal rule, etc. Not sure if that's possible either though...
There is no concept of "lists" (as a separate data structure) in T-SQL. Does this do what you want?
SELECT *
FROM table
WHERE id IN (26275, 54374, 84567);
declare #i int = 0;
declare #Id int;
declare #Ids table (Id int);
insert #Ids select Id from (values (26275), (54374), (84567)) t(Id);
-- OR: insert #Ids select * from string_split('26275, 54374, 84567', ',');
declare #Count int = (select count(*) from #Ids);
while #i < #Count
begin
select #Id = Id, #i = #i + 1
from #Ids order by Id
offset #i rows fetch next 1 rows only;
select * from dbo.MyTable where Id = #Id;
end
You can use UNION ALL:
SELECT * FROM table WHERE id = 26275
UNION ALL
SELECT * FROM table WHERE id = 54374
UNION ALL
SELECT * FROM table WHERE id = 84567

SQL - Variable assignment with other columns selection

I am trying to get the records as well as records count using common table expressions, but I want to store the records count in a variable and it will ofcourse give me the error
A SELECT statement that assigns a value to a variable must not be
combined with data-retrieval operations.
I am trying something like this
declare #count int
;with allRecords as
(
-- query fetching all the records with many joins
),
recordsCount as
(
select count(*) as Total from allRecords
)
select allRecords.*, #count=recordsCount.Total from allRecords, recordsCount
where -- multiple conditions
Is there any work around for this?
Actually the #count variable is an output variable of my stored procedure so I want to return the result as well as fill this #count variable
You can't do it like this. If you want to get the number of rows the select statement returned into a variable you should use the built-in global variable ##ROWCOUNT:
DECLARE #count int
;WITH allRecords as
(
-- query fetching all the records with many joins
)
SELECT allRecords.*
FROM allRecords
SELECT #Count = ##ROWCOUNT
Update:
Well, in that case you have no choise that I'm aware of other then using a temporary table:
SELECT /* columns */ INTO #tempTableName
-- rest of the select statement
SELECT #Count = COUNT(*)
FROM #tempTableName
SELECT *
FROM #tempTableName
WHERE <conditions>
DROP TABLE #tempTableName
declare #count int
;with allRecords as
(
-- query fetching all the records with many joins
)
select #count = count(*) as Total from allRecords
I'd use a temp table or table variable here. You can then do separate statements for select #count = count(*) from #allrecords and select * from #allrecords

Is there any way to select records if top clause parameter is null?

Is there any way to select records if top clause parameter is null?
DECLARE #count FLOAT = 0;
Select #count = count from tblDetails
SELECT TOP(#count) from tblCompany
If #count var is null than i want to select all records from tblCompany.
DECLARE #count FLOAT = 0;
Select #count = count(1) from tblDetails
IF #count > 0
BEGIN
SELECT TOP(#intRecords) * from tblCompany
END
ELSE
BEGIN
SELECT * FROM tblCompany
END
If you do not want to write the query twice - although only one will get executed, you can try this:
DECLARE #count FLOAT = 0;
Select #count = count(1) from tblDetails
IF #count = 0
BEGIN
SET #intRecords = 100000 -- Or some number larger than the possible count
END
SELECT TOP(#intRecords) * from tblCompany
When facing situations like this one, I love using SQL Rank.
In the query below I assumed you have an ID column, but you can replace it with any other column for choosing the criteria for what would be considered to be the top columns:
DECLARE #count FLOAT = 0;
Select #count = count(*) from tblDetails
SELECT * FROM
(
SELECT
RANK () OVER
( ORDER BY ID ) 'Rank', -- <-- Assuming you have an ID column, replace with any other criteria for what will be considered as top...
*
FROM tblCompany
) tmp
WHERE (#count IS NULL) OR tmp.Rank <= #count
I think this would work:
DECLARE #count AS INT ;
Set #count = (Select count(*) from tblDetails);
SELECT TOP(ISNULL(#count,5)) * from tblCompany

Store Procedure Select into a variable

How can I count the result of a table and pass into a Stored Procedure Variable?
DECLARE #totalrecs varchar
select count(id) from table1
I want the count record in the totalrecs variable.
like this
--will not count NULLS
select #totalrecs= count(id) from table1
--will count NULLS
select #totalrecs= count(*) from table1
DECLARE #totalCount Int
Select #totalCount = count(*)
From table1
Exec sp_DoSomething #Var = #totalCount
select #totalrecs= count(id) from table1

How can I use if statement after a CTE (SQL Server 2005)

Last night I was writing a simple T-SQL program something like this
DECLARE #ROLEID AS INT
SELECT #ROLEID = [ROLE ID] FROM TBLROLE
;WITH CTE
AS
(
SELECT * FROM SOMETABLE
)
IF (#ROLEID = 1)
BEGIN
//SOMECODE
END
ELSE IF(#ROLEID = 2)
BEGIN
//SOMECODE
END
ELSE
BEGIN
//SOMECODE
END
I found after compilation that it is throwing error something like "Incorrect statement near if"
What is wrong?
However, I did that by using some other way. But I wanted to know why it did not work!
Common table expressions are defined within the context of a single statement:
WITH cte_name AS (
<cte definition>)
<statement that uses cte>;
So you can do something like:
WITH CTE
AS
(
SELECT * FROM SOMETABLE
)
SELECT * FROM CTE;
or
WITH CTE
AS
(
SELECT * FROM SOMETABLE
)
UPDATE CTE
SET somefield = somevalue
WHERE id = somekey;
A CTE must be followed by a single
SELECT, INSERT, UPDATE, MERGE, or
DELETE statement that references some
or all the CTE columns. A CTE can also
be specified in a CREATE VIEW
statement as part of the defining
SELECT statement of the view
A little late but I can't be the only one bumping into this.
A solution could be to create a temporary table like this:
-- If previous run of this query fails, the temp table will be deleted.
-- Selecting into creates the temp table which fails if it already exists
IF EXISTS(SELECT [name] FROM tempdb.sys.tables WHERE [name] like '#dtBalansOpgesteldGefilterd%') BEGIN
DROP TABLE #temp
END;
;WITH CTE
AS
(
SELECT * FROM SOMETABLE
)
-- Followed by select statement as required
SELECT *
INTO #temp
FROM CTE
IF #awsome = 1
BEGIN
SELECT 'WHATEVERYOUWANT' AS WhateverColumnNameYouWant, *
FROM #temp
END
The closest you'll get is using a UNION ALL to do a crude switched select:
DECLARE #ROLEID AS INT
SELECT #ROLEID = [ROLE ID] FROM TBLROLE
;WITH CTE
AS
(
SELECT * FROM SOMETABLE
)
SELECT
--somecolumns
FROM
CTE
--other stuff too
WHERE
#ROLEID = 1
UNION ALL
SELECT
--somecolumns
FROM
CTE
--other stuff too
WHERE
#ROLEID = 2
UNION ALL
SELECT
--somecolumns
FROM
CTE
--other stuff too
WHERE
#ROLEID = 3
...
UNION ALL
SELECT
--somecolumns
FROM
CTE
--other stuff too
WHERE
#ROLEID = n
Try putting the CTE in the IF. It worked for me.
IF #awsome = 1
BEGIN
;WITH CTE
AS
(
SELECT * FROM SOMETABLE
)
SELECT 'WHATEVERYOUWANT' FROM CTE
END
ELSE IF #awesome = 2
BEGIN
;WITH CTE2
AS
(
SELECT * FROM SOMETABLE
)
SELECT 'WHATEVERYOUWANT' FROM CTE2
END