SQL - Variable assignment with other columns selection - sql

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

Related

nested select query with table name in sqlite

I am trying to select all distinct values from all tables that start with a specific name, like: 'logs_2020_12_01', 'logs_2021_01_02', ..To select all tables with this specific name is straight forward:
SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'logs_%';
The select I want for one individual table is:
SELECT DISTINCT batch FROM logs_2021_01_27;
but I cannot find a way to combine it to make the selection from all tables. I tried a couple of things but it does not work, like:
SELECT DISTINCT batch FROM (SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'logs_%')
any ideas?
thanks
What about using Dynamic SQL, stored your tables information into a temp table with id column and set it to identity.
CREATE TABLE #temp ---identity column will be used to iterate
(
id INT IDENTITY,
TableName VARCHAR(20)
)
INSERT INTO #temp
SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'logs_%';
-- choose your own results with where conditions
DECLARE #SQL VARCHAR(MAX)
DECLARE #Count INT = 1
DECLARE #Table VARCHAR(20)
WHILE #COUNT <= (SELECT COUNT(*) FROM #temp)
BEGIN
select #table = TABLENAME FROM #temp WHERE id = #Count
SELECT #sql = 'SELECT DISTINCT(batch) FROM '+ #table
PRINT #SQL
SET #Count = #Count + 1
END
after your print result looks good, change it to EXEC(#SQL), thanks
SQLite does not support dynamic sql.
You have to select the column batch from each of all the tables and combine them with UNION so the duplicates are removed:
SELECT batch FROM logs_2020_12_01 UNION
SELECT batch FROM logs_2020_12_02 UNION
......................................
SELECT batch FROM logs_2020_12_30 UNION
SELECT batch FROM logs_2020_12_31
If you don't know the full names of the tables, you can get them with this statement:
SELECT name
FROM sqlite_master
WHERE type = 'table' AND name LIKE 'logs/_%' ESCAPE '/'
and then use a programming language to construct a SELECT statement with UNION to get the results that you want.

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

How to use WITH result table multiple times?

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

Use top based on condition

I have a parameter in my stored procedure that specifies number of rows to select. (Possible values: 0-100. 0 Means Select All rows)
For example #Rows = 5;
Then I can do this:
Insert into #MyTableVar
Select Top(#Rows) *
from myTable
Now, as I said before if 0 is supplied I need to return all rows.
This is a pseudo-code of what I need:
if (#Rows=0) then select * else select top(#Rows) *
I found out that there's SET ROWCOUNT that accepts 0 to return ALL rows, but I need to do an insert into a table variable which is not supported by ROWCOUNT.
Is it possible to achieve this without dynamic sql?
(I understand that I can write a simple if else statement and duplicate query, but I have pretty complex queries and there are lots fo them, I just want to avoid code duplication)
One way is to just put a big number in:
set #Rows = 5;
declare #RowsToUse = (case when #Rows = 0 then 1000000000 else #Rows end);
select top(#RowsToUse) * from myTable
First of all, you are missing the ORDER BY clause, since you are using TOP. You could do this:
SET #Rows = 5;
WITH CTE AS
(
SELECT *,
RN = ROW_NUMBER() OVER(ORDER BY Id) --put the right order here
FROM myTable
)
INSERT INTO #MyTableVar
SELECT YourColumns
FROM CTE
WHERE RN <= #Rows OR #Rows = 0

top count for a SQL query

I want to have a variable for selecting top rows. I can select top rows based on a variable. However I want to select all rows if the variable is not supplied.
Currently I'm using this query:
DECLARE #TOPCOUNT int;
SET #TOPCOUNT=10;
SELECT TOP(#TOPCOUNT) * FROM TABLE1
Update:
The original query is very lengthy and complex, so I don't to rewrite the entire query without top count in else clause.
I don't want to use dynamic query because of its repercussions.
Something like this:
DECLARE #TOPCOUNT int;
--SET #TOPCOUNT=10;
IF #TOPCOUNT IS NULL
SELECT * FROM TABLE1
ELSE
SELECT TOP(#TOPCOUNT) * FROM TABLE1
Added after above UPDATE - if this is a parameter of a Stored Procedure then just provide a default for #TOPCOUNT:
#TOPCOUNT INT = 2147483647 --max size of INT
Something like this will help. Just init your #TOPCOUNT with -1 if you want all rows.
IF #TOPCOUNT = -1 BEGIN
SELECT * FROM TABLE1
END
ELSE BEGIN
SELECT TOP(#TOPCOUNT) * FROM TABLE1
END
IF #TOPCOUNT IS NULL SET #TOPCOUNT=2147483647