top count for a SQL query - sql

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

Related

Finding row until condition is met

This is my table:
PackingNr
SerienNr
PN185971
PN185972
PN185972
PN185974
PN185974
PN185978
PN185978
R005478
PN185968
R000547
PN185725
R004987
As an input I get PackingNr and I need to select SerienNr which is like Rxxxxx not PNxxxxx.
So for example, if I have input PN175971, I need to get SerienNr = R005478.
How can I do this inside of select query? I tried CASE but this won't work as I don't know how many times I have to go again.
My select query is selecting also other columns from different tables.
SELECT
... ,
CASE
WHEN PSPD.SerienNr LIKE '%PN%'
THEN
(SELECT SerienNr FROM PSAPacking_Det
WHERE PSAPacking_Det.PackingNr = PSPD.SerienNr)
ELSE PSPD.SerienNr
END AS SerienNr
...
FROM
PSAPacking PSPD
JOIN
...
WHERE
PSPD.PackingNr = 'PN185971'
You need a recursive CTE. Something like this:
WITH cte AS (
SELECT t.PackingNr, t.SerienNr
FROM YourTable t
WHERE t..PackingNr = 'YourValueHere'
UNION ALL
SELECT t.PackingNr, t.SerienNr
FROM YourTable t
JOIN cte ON cte.SerienNr = t.PackingNr
)
SELECT TOP (1)
*
FROM cte
WHERE cte.SerienNr LIKE 'R%';
try this
declare #var2 varchar(max) = 'PN185971' --PUT YOUR INPUT HERE
declare #var1 varchar(max);
while(#var2 not like 'R%')
begin
set #var1 = #var2
set #var2 = (select max(SerienNr) from PSAPacking where PackingNr = #var1)
end
select #var2
if it doesn't find the value starting with R it returns null

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

Dynamic TOP N / TOP 100 PERCENT in a single query based on condition

A local variable #V_COUNT INT. If the variable #V_COUNT is '0'(zero) the return all the records from table otherwise return the number of {#V_COUNT} records from table. For example if #V_COUNT = 50, return TOP 50 records. If #V_COUNT is 0 then return TOP 100 PERCENT records. Can we achieve this in a single query?
Sample query :
DECLARE #V_COUNT INT = 0
SELECT TOP (CASE WHEN #V_COUNT > 0 THEN #V_COUNT ELSE 100 PERCENT END) *
FROM MY_TABLE
ORDER BY COL1
Incorrect syntax near the keyword 'percent'
A better solution would be to not use TOP at all - but ROWCOUNT instead:
SET ROWCOUNT stops processing after the specified number of rows.
...
To return all rows, set ROWCOUNT to 0.
Please note that ROWCOUNT is recommended to use only with select statements -
Important
Using SET ROWCOUNT will not affect DELETE, INSERT, and UPDATE statements in a future release of SQL Server. Avoid using SET ROWCOUNT with DELETE, INSERT, and UPDATE statements in new development work, and plan to modify applications that currently use it. For a similar behavior, use the TOP syntax.
DECLARE #V_COUNT INT = 0
SET ROWCOUNT #V_COUNT -- 0 means return all rows...
SELECT *
FROM MY_TABLE
ORDER BY COL1
SET ROWCOUNT 0 -- Avoid side effects...
This will eliminate the need to know how many rows there are in the table
Be sure to re-set the ROWCOUNT back to 0 after the query, to avoid side effects (Good point by Shnugo in the comments).
Instead of 100 percent you can write some very big number, which will surely be bigger than possible number of rows returned by the query, eg. max int which is 2147483647.
You can do something like:
DECLARE #V_COUNT INT = 0
SELECT TOP (CASE WHEN #V_COUNT > 0 THEN #V_COUNT ELSE (SELECT COUNT(1) FROM MY_TABLE) END) *
FROM MY_TABLE
DECLARE #V_COUNT int = 3
select *
from
MY_TABLE
ORDER BY
Service_Id asc
offset case when #V_COUNT >0 then ((select count(*) from MY_TABLE)- #V_COUNT) else #V_COUNT end rows
SET ROWCOUNT forces you into procedural logic. Furthermore, you'll have to provide an absolute number. PERCENT would need some kind of computation...
You might try this:
DECLARE #Percent FLOAT = 50;
SELECT TOP (SELECT CAST(CAST((SELECT COUNT(*) FROM sys.objects) AS FLOAT)/100.0 * CASE WHEN #Percent=0 THEN 100 ELSE #Percent END +1 AS INT)) o.*
FROM sys.objects o
ORDER BY o.[name];
This looks a bit clumsy, but the computation will be done once within microseconds...

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

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