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

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

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

declaring multiple columns in a count value

I am trying to define multiple count values for a counter and corresponding value. Here is my code:
DECLARE #RequestDate AS DATE = '2017-04-20'
;
DECLARE #POCounter INT;
DECLARE #POMax INT;
DECLARE #NewDate DATE;
SET #POCounter = 0;
SET #POMax =
(
SELECT
CUSTOMERPONUMBER,
(
SELECT
COUNT(CUSTOMERPONUMBER)
FROM DailyOpenOrders$
WHERE
RequestDate < #RequestDate
)
FROM DailyOpenOrders$
WHERE
RequestDate < #RequestDate
GROUP BY
CUSTOMERPONUMBER
)
The #POMax counter is to help me update the date that many times for a specific customerPO. I intend to increase the POCounter in a loop until it reaches the #POmax counter for each customerPOnumber.
Am i doing this wrong? can someone help?
#POMax is a scalar variable and can only hold one value at a time.
If you want to hold a collection of values, a table variable is a good tool for that:
DECLARE #MyTable TABLE
(
ID int PRIMARY KEY IDENTITY(1,1),
CustomerNumber varchar(50),
[TheCount] int
)
INSERT INTO #MyTable(CustomerNumber, [TheCount])
SELECT CustomerNumber, COUNT(*)
FROM SomeTable
GROUP BY CustomerNumber
Now you can loop over #MyTable, and for each CustomerNumber, loop from 1 to TheCount...
DECLARE #MyID int
SET #MyID = (SELECT MIN(ID) FROM #MyTable)
WHILE #MyID is not null
BEGIN
SELECT * FROM #MyTable WHERE ID = #MyID
SET #MyID = (SELECT MIN(ID) FROM #MyTable WHERE #MyID < ID)
END

Use top 1 and then delete?

I have a table #tmpName with just one column, [Name].
Without using a cursor, I would like to take each row of #tmpName (which is technically one name), do something with that name, and then delete from #tmpName.
I began with something like this, but it's very slow and I eventually get an out of memory exception, which doesn't make sense on a 700-row table. I assume it has to do with the fact that I'm not ordering when doing a delete top 1.
drop table #tmpName ;
with cte as (
select Name from [Employees]
group by Name
)
select Name into #tmpName From cte
declare #count int = 0
while ##rowcount <> 0
begin
select top 1 Name From #tmpName order by Name asc
--do stuff with top 1
delete top (1) from #tmpName
select #count = #count + 1
select #count
END
I figured then that I could use this DELETE to better remove TOP 1, but I'm not sure how to process each one I delete.
WITH q AS
(
SELECT TOP 1 Name into #Name
FROM #tmpName
order by Name
)
DELETE
FROM q
any help is appreciated.
-- once you have data in the temp table, you could something like this....
-- populate temp table
select Name INTO #tmpName
from [Employees]
group by Name
DECLARE #Name VARCHAR(100);
while EXISTS(SELECT * FROM #tmpName)
BEGIN
select top 1 #Name = Name From #tmpName
-- do stuff with top 1
delete from #tmpName WHERE Name = #Name
END
Perhaps you should consider a cursor. You can do what you want with the output clause:
DECLARE #namet (name varchar(255));
WITH todelete as (
SELECT TOP 1 Name
FROM #tmpName
ORDER BY Name
)
DELETE FROM todelete
OUTPUT name into #namet;
SELECT #name = name FROM #namet;
You can put this logic into a loop.
However, I would recommend that you just add another column to the table and enumerate that.
drop table #tmpName ;
select row_number() over(order by Name) as rn, Name
into #tmpName From [Employees];
declare #count int = (select count(*) from #tmpName)
declare #rn int = 1
while #count > 0
begin
select Name From #tmpName where rn = #rn
--do stuff with top 1
delete from #tmpName where rn = #rn
set #count = #count - 1
set #rn = #rn+1
select #count
end
A cte is not needed. You can try this.

How to store result of a select statement into a variable?

I tried with the below code:
DECLARE #rec_count int
Set #rec_count= select 1
but it shows error
"Incorrect syntax near Select".
Either:
set #rec_count = (select 1)
or
select #rec_count = 1
An example assigning the count from a table to variable:
set #rec_count = (select COUNT(*) from master..spt_values)
select #rec_count = COUNT(*) from master..spt_values
However, if you just want to assign a value to a variable you don't need any select statement:
set #rec_count = 1
or
declare #rec_count int = 1
To store the result of a select statement into a variable, see below
DECLARE #rec_count INT
SELECT #rec_count = 1
We can get more than one value from select statement as below
DECLARE #rec_count INT
DECLARE #date DATETIME
SELECT #rec_count = 1, #date = GETDATE()
If you're trying to get a record count, which looks like what you're trying to do, you can do this:
declare #rec_count int
select #rec_count = count(1) from [your_table] -- where some condition is met
Note: Use count(1) instead of count(*) as it's quicker to simply select a single column than all when getting a count.
Or if this count is the result of some inserts/updates/selects/deletes, you can use the ##ROWCOUNT, which:
Returns the number of rows affected by the last statement.
So if for example you are performing an update or select and want to know how many rows were affected, it will automatically be stored by SQL Server in the ##ROWCOUNT.
declare #rec_count int
-- some table change
update your_table
set col1 = 1
where col1 = 0
set #rec_count = ##ROWCOUNT
-- select ##ROWCOUNT <-- this would return the number of rows updated
DECLARE #rec_count int;
Set #rec_count = 1;

SELECT TOP 1, 2, 3 RowId from TableWithNRows

Stupid problem and the answer may not exists (Gasp! Groan! Gnash! Teeth!)
I have a select:
SELECT * FROM SockDrawer WHERE Color = 'red'
This results in 3 rows with row ids of 33896, 35901, 37903
(A lot of other results too.)
What I want is something like this:
DECLARE #ROWID INT --- HOW DO I USE ARRAYS? I'll google but an example would help.
DECLARE #COUNT INT
DECLARE #LIMIT INT
SELECT * FROM SockDrawer WHERE Color = 'red'
--(Returns 3 rows. With 3 RowId's 33896, 35901, 33896)
SET #LIMIT = ##ROWCOUNT
SET #COUNT = 1
WHILE #COUNT < #LIMIT BEGIN
SET #ROWID[0] = (SELECT SockKey From SockDrawer WHERE RowID = 33896)
SET #ROWID[1] = (SELECT SockKey From SockDrawer WHERE RowID = 35901)
SET #ROWID[2] = (SELECT SockKey From SockDrawer WHERE RowID = 33896)
SET #Count = #Count + 1
END
GO
Then I need to:
SET #COUNT = 0
WHILE #COUNT < #LIMIT
BEGIN
DELETE FROM SockDrawer WHERE RowID = #ROWID[#COUNT]
END
GO
The trick is I'll never know if I'm dealing with 1 row to delete or 50.
I'm a dork. I can change. If I want to.
If you don't care about which sock is left for each color, then:
;WITH x AS
(
SELECT *, rn = ROW_NUMBER() OVER (PARTITION BY Color ORDER BY RowID)
FROM dbo.SockDrawer
)
DELETE x WHERE rn > 1;
If you care which one you keep, adjust the ORDER BY accordingly.