COUNT in CASE - SQL Server - sql-server

Is it possible to do a value assignment with a COUNT() as the when clause?
Like so:
SELECT #value =
CASE
WHEN
COUNT(tableID)
FROM (SELECT TOP (5) tableID FROM table) AS id = 20
THEN 'Looks Good'
END
I basically what to select a variable amount of rows [TOP (#rowCount)], then take action based on the number of rows counted. I'm sure I can do this someway somehow, guessing I'm just missing something in the syntax.

If you're looking for code branching, the following would work:
IF 20 = (select count(*)
from (select top (5) tableID from table) as id)
PRINT 'Looks Good'
ELSE
PRINT '5 will never equal 20'
If you want to get or set a value, one of the following would work:
SELECT case count(*)
when 20 then 'good'
else 'bad'
end
from (select top (5) tableID from table) as id
or
SELECT case
when count(*) > 5 then 'Over 5'
when count(*) < 5 then 'Under 5'
else 'Exactly 5'
end
from (select top (5) tableID from table) as id

Not sure if I understand the question, but maybe try something like
select #val = case when the_number >= 20 then 'Looks good' end
from (
select count(*) the_number from some_table
) x

Assuming you are using at least sql2005 or greater then this will work -
--create a table to test with
create table #TestTable
(
TestTableID int primary key
)
--populate test table
declare #i int = 0;
while #i < 10
begin
insert into #TestTable select #i;
set #i = #i + 1;
end
GO
--now create variables to hold the TOP value and to store the result
declare #a int = 5
,#value varchar(10);
--correct case stmt syntax
set #value = case
when (select count(RecordList) as 'RecordListCount' from (select top (#a) TestTableID as 'RecordList' from #TestTable) as sq) = 20 then 'Looks Good'
else 'Looks Bad'
end;
select #value;
Remember to put the TOP variable in parentheses and to supply aliases for all of the tables and columns.
I hope that helps!

I think I understood your question. You want to know if it is possible to have TOP N rows of table, when N is variable.
If I am right, you will need to specify a column which the table would be ordered.
Then you can use something like:
SELECT *
FROM (
SELECT *, ROW_NUMBER() OVER (ORDER BY COLUMN_NAME) TOPCOL
FROM TABLE_NAME
) A
WHERE TOPCOL <= N
If I am not right, you should edit your question, because it is very hard to understand what you meant

Related

How to fiind out the missing records (ID) from an indexed [order] table in sql

I have a table [Order] that has records with sequential ID (in odd number only, i.e. 1,3,5,7...989, 991, 993, 995, 997, 999), it is seen that a few records were accidentally deleted and should be inserted back, first thing is to find out what records are missing in the current table, there are hundreds of records in this table
Don't know how to write the query, can anyone kindly help, please?
I am thinking if I have to write a stored procedure or function but would be better if I can avoid them for environment reasons.
Below peuso code is what I am thinking:
set #MaxValue = Max(numberfield)
set #TestValue = 1
open cursor on recordset ordered by numberfield
foreach numberfield
while (numberfield != #testvalue) and (#testvalue < #MaxValue) then
Insert #testvalue into #temp table
set #testvalue = #textvalue + 2
Next
Next
UPDATE:
Expected result:
Order ID = 7 should be picked up as the only missing record.
Update 2:
If I use
WHERE
o.id IS NULL;
It returns nothing:
Since I didn't get a response from you, in the comments, I've altered the script for you to fill in accordingly:
declare #id int
declare #maxid int
set #id = 1
select #maxid = max([Your ID Column Name]) from [Your Table Name]
declare #IDseq table (id int)
while #id < #maxid --whatever you max is
begin
insert into #IDseq values(#id)
set #id = #id + 1
end
select
s.id
from #IDseq s
left join [Your Table Name] t on s.id = t.[Your ID Column Name]
where t.[Your ID Column Name] is null
Where you see [Your ID Column Name], replace everything with your column name and the same goes for [Your Table Name].
I'm sure this will give you the results you seek.
We can try joining to a number table, which contains all the odd numbers which you might expect to appear in your own table.
DECLARE #start int = 1
DECLARE #end int = 1000
WITH cte AS (
SELECT #start num
UNION ALL
SELECT num + 2 FROM cte WHERE num < #end
)
SELECT num
FROM cte t
LEFT JOIN [Order] o
ON t.num = o.numberfield
WHERE
o.numberfield IS NULL;

SQL add conditional query

In a table in my database I have 12 columns, month_1 .... month_12.
I want to add conditional to my SQL query, if #m = 1 will do
CREATE PROCEDURE XemDiem_Top5Month1
#m INT
AS
BEGIN
SELECT *
FROM XemDiem
WHERE (month_1 IN (SELECT TOP (5) month_1
FROM XemDiem
GROUP BY month_1
ORDER BY month_1DESC))
END
if #m = 2 will do
CREATE PROCEDURE XemDiem_Top5Month1
#m INT
AS
BEGIN
SELECT *
FROM XemDiem
WHERE (month_2 IN (SELECT TOP (5) month_2
FROM XemDiem
GROUP BY month_2
ORDER BY month_2 DESC))
END
and so on ....
I don't want to write too many queries, so please help
Assign the select query to a string and concatenate your parameter. Finally execute the string.
Create proc XemDiem_Top5Month1
#m int
AS
BEGIN
Delcare #query nvarchar(max)
set #query='SELECT *
FROM XemDiem
WHERE
(
month_''+Convert(varchar(10),#m)+'' IN
(
SELECT TOP (5) month_''+Convert(varchar(10),#m)+''
FROM XemDiem
GROUP BY month_''+Convert(varchar(10),#m)+''
ORDER BY month_''+Convert(varchar(10),#m)+'' DESC
)
)'
execute(#query)
declare #ishistoric varchar(100) ='month_1'
(SELECT *
FROM XemDiem
WHERE
(
CASE #ishistoric
WHEN 'month_1' THEN month_1
WHEN 'month_2' THEN month_2
...
WHEN 'month_12' THEN month_12
END IN
(
SELECT TOP (5) CASE #ishistoric
WHEN 'month_1' THEN month_1
WHEN 'month_2' THEN month_2
...
WHEN 'month_12' THEN month_12
END
FROM OSUSR_KIA_PRINTSTICKER
GROUP BY CASE #ishistoric
WHEN 'month_1' THEN month_1
WHEN 'month_2' THEN month_2
...
WHEN 'month_12' THEN month_12
END
ORDER BY CASE #ishistoric
WHEN 'month_1' THEN month_1
WHEN 'month_2' THEN month_2
...
WHEN 'month_12' THEN month_12
END DESC
)
))
Make your remain query just like that and query is based on the provided columns & it will the return respective records for specific column which are passed into the parameter.

creating table and using if statement

I have this question which I don't really understand
I need help understanding or answering it
--Create the table on the fly with the condition stated
SELECT
TEAM_NAME,
RACES_COMPETED
INTO [TOP TEAMS]
FROM YourTable
WHERE RACES_COMPETED >= 500 and RACES_COMPETED <= 900
--Store the number of teams in the new table in a variable for ease of use
DECLARE #topTeams INT
SET #topTeams = (SELECT COUNT(*) FROM [TOP TEAMS])
--If there are teams in the table, print the number of teams. If there aren't any, print the other statment
IF #topTeams > 0
BEGIN
SELECT 'NO. OF TOP TEAMS: ' + CAST(#topTeams AS VARCHAR)
END
ELSE
BEGIN
SELECT 'NO TOP TEAMS EXIST'
END
HERE IS THE SAME CODE USING A TEMP TALBE
--Drop the TEMP TABLE if it exists
IF OBJECT_ID('tempdb..#TOP_TEAMS') IS NOT NULL DROP TABLE #TOP_TEAMS
--Create the table on the fly with the condition stated
SELECT
TEAM_NAME,
RACES_COMPETED
INTO #TOP_TEAMS
FROM YourTable
WHERE RACES_COMPETED >= 500 and RACES_COMPETED <= 900
--Store the number of teams in the new table in a variable for ease of use
DECLARE #topTeams INT
SET #topTeams = (SELECT COUNT(*) FROM #TOP_TEAMS)
--If there are teams in the table, print the number of teams. If there aren't any, print the other statment
IF #topTeams > 0
BEGIN
SELECT 'NO. OF TOP TEAMS: ' + CAST(#topTeams AS VARCHAR)
END
ELSE
BEGIN
SELECT 'NO TOP TEAMS EXIST'
END

TSQL calculating sum of numerous fields

I have this kind of data:
Date Count1 Count2 Count3 ... Countxx
01-05-2012 1 0 1 2
01-05-2012 2 1 3 0
01-05-2012 2 3 3 1
02-05-2012 1 3 2 0
02-05-2012 5 2 0 0
and I need to calculate sum of respective fields (Count1 to Countxx) grouped by date and wrote this SQL:
select sum(count1), sum(count2), sum(count3), .. , sum(countxx)
from table1 group by date
my first question: is there any way in SQL server to do this automatically (without knowing number of fields, since the name and number of the fields will be different each time, thus making writing the SQL manually very cumbersome).
secondly, how to calculate value from current row minus previous row, and average of previous 7 rows?
Thanks!
create procedure USP_FindSum #tablename varchar(100)
as
begin
create table #temp(id int identity(1,1),name varchar(100))
declare #sqlcmd nvarchar(max)=''
SET #sqlcmd= N'Insert into #temp select name from sys.columns col_table where
col_table.object_id=object_id('''+#tablename+''')'
EXEC sp_executesql #sqlcmd
declare #sqlseg varchar(max)=''
declare #tempcount int
declare #i int=1
select #tempcount=COUNT(id) from #temp
while(#i<=#tempcount)
BEGIN
declare #CName varchar(100)
SELECT #CName= name from #temp where id=#i
if(#i!=#tempcount)
SET #sqlseg=+#sqlseg+'sum('+#CName+')'+','
else
SET #sqlseg =+#sqlseg+'sum('+#CName+')'
SET #i=#i+1
END
SET #sqlcmd=N'select '+#sqlseg+' from '+#tablename
EXEC sp_executesql #sqlcmd
DROP TABLE #temp
END
Assuming all the columns in the table are summable. As your requirement is weird this workaround may also be so.
Just pass the table name as parameter and execute,
Exec USP_FindSum '<tablename here>'
There is no way to sum a variable list of columns, you have to specify them all.
One way to look up the previous row is outer apply, like:
select Date
, cur.count1 - isnull(prev.count1,0) as Delta1
from Table1 cur
outer apply
(
select top 1 *
from Table1 prev
where prev.Date < cur.Date
order by
prev.Date desc
) prev
Another way is to join the tables based on row_number():
; with t1 as
(
select row_number() over (order by Date) as rn
, *
from Table1
)
select Date,
, cur.count1 - isnull(prev.count1,0) as Delta
from t1 cur
left join
t1 prev
on cur.rn = prev.rn + 1

SQL Server: UPDATE a table by using ORDER BY

I would like to know if there is a way to use an order by clause when updating a table. I am updating a table and setting a consecutive number, that's why the order of the update is important. Using the following sql statement, I was able to solve it without using a cursor:
DECLARE #Number INT = 0
UPDATE Test
SET #Number = Number = #Number +1
now what I'd like to to do is an order by clause like so:
DECLARE #Number INT = 0
UPDATE Test
SET #Number = Number = #Number +1
ORDER BY Test.Id DESC
I've read: How to update and order by using ms sql The solutions to this question do not solve the ordering problem - they just filter the items on which the update is applied.
Take care,
Martin
No.
Not a documented 100% supported way. There is an approach sometimes used for calculating running totals called "quirky update" that suggests that it might update in order of clustered index if certain conditions are met but as far as I know this relies completely on empirical observation rather than any guarantee.
But what version of SQL Server are you on? If SQL2005+ you might be able to do something with row_number and a CTE (You can update the CTE)
With cte As
(
SELECT id,Number,
ROW_NUMBER() OVER (ORDER BY id DESC) AS RN
FROM Test
)
UPDATE cte SET Number=RN
You can not use ORDER BY as part of the UPDATE statement (you can use in sub-selects that are part of the update).
UPDATE Test
SET Number = rowNumber
FROM Test
INNER JOIN
(SELECT ID, row_number() OVER (ORDER BY ID DESC) as rowNumber
FROM Test) drRowNumbers ON drRowNumbers.ID = Test.ID
Edit
Following solution could have problems with clustered indexes involved as mentioned here. Thanks to Martin for pointing this out.
The answer is kept to educate those (like me) who don't know all side-effects or ins and outs of SQL Server.
Expanding on the answer gaven by Quassnoi in your link, following works
DECLARE #Test TABLE (Number INTEGER, AText VARCHAR(2), ID INTEGER)
DECLARE #Number INT
INSERT INTO #Test VALUES (1, 'A', 1)
INSERT INTO #Test VALUES (2, 'B', 2)
INSERT INTO #Test VALUES (1, 'E', 5)
INSERT INTO #Test VALUES (3, 'C', 3)
INSERT INTO #Test VALUES (2, 'D', 4)
SET #Number = 0
;WITH q AS (
SELECT TOP 1000000 *
FROM #Test
ORDER BY
ID
)
UPDATE q
SET #Number = Number = #Number + 1
The row_number() function would be the best approach to this problem.
UPDATE T
SET T.Number = R.rowNum
FROM Test T
JOIN (
SELECT T2.id,row_number() over (order by T2.Id desc) rowNum from Test T2
) R on T.id=R.id
update based on Ordering by the order of values in a SQL IN() clause
Solution:
DECLARE #counter int
SET #counter = 0
;WITH q AS
(
select * from Products WHERE ID in (SELECT TOP (10) ID FROM Products WHERE ID IN( 3,2,1)
ORDER BY ID DESC)
)
update q set Display= #counter, #counter = #counter + 1
This updates based on descending 3,2,1
Hope helps someone.
I had a similar problem and solved it using ROW_NUMBER() in combination with the OVER keyword. The task was to retrospectively populate a new TicketNo (integer) field in a simple table based on the original CreatedDate, and grouped by ModuleId - so that ticket numbers started at 1 within each Module group and incremented by date. The table already had a TicketID primary key (a GUID).
Here's the SQL:
UPDATE Tickets SET TicketNo=T2.RowNo
FROM Tickets
INNER JOIN
(select TicketID, TicketNo,
ROW_NUMBER() OVER (PARTITION BY ModuleId ORDER BY DateCreated) AS RowNo from Tickets)
AS T2 ON T2.TicketID = Tickets.TicketID
Worked a treat!
I ran into the same problem and was able to resolve it in very powerful way that allows unlimited sorting possibilities.
I created a View using (saving) 2 sort orders (*explanation on how to do so below).
After that I simply applied the update queries to the View created and it worked great.
Here are the 2 queries I used on the view:
1st Query:
Update MyView
Set SortID=0
2nd Query:
DECLARE #sortID int
SET #sortID = 0
UPDATE MyView
SET #sortID = sortID = #sortID + 1
*To be able to save the sorting on the View I put TOP into the SELECT statement. This very useful workaround allows the View results to be returned sorted as set when the View was created when the View is opened. In my case it looked like:
(NOTE: Using this workaround will place an big load on the server if using a large table and it is therefore recommended to include as few fields as possible in the view if working with large tables)
SELECT TOP (600000)
dbo.Items.ID, dbo.Items.Code, dbo.Items.SortID, dbo.Supplier.Date,
dbo.Supplier.Code AS Expr1
FROM dbo.Items INNER JOIN
dbo.Supplier ON dbo.Items.SupplierCode = dbo.Supplier.Code
ORDER BY dbo.Supplier.Date, dbo.Items.ID DESC
Running: SQL Server 2005 on a Windows Server 2003
Additional Keywords: How to Update a SQL column with Ascending or Descending Numbers - Numeric Values / how to set order in SQL update statement / how to save order by in sql view / increment sql update / auto autoincrement sql update / create sql field with ascending numbers
SET #pos := 0;
UPDATE TABLE_NAME SET Roll_No = ( SELECT #pos := #pos + 1 ) ORDER BY First_Name ASC;
In the above example query simply update the student Roll_No column depending on the student Frist_Name column. From 1 to No_of_records in the table. I hope it's clear now.
IF OBJECT_ID('tempdb..#TAB') IS NOT NULL
BEGIN
DROP TABLE #TAB
END
CREATE TABLE #TAB(CH1 INT,CH2 INT,CH3 INT)
DECLARE #CH2 INT = NULL , #CH3 INT=NULL,#SPID INT=NULL,#SQL NVARCHAR(4000)='', #ParmDefinition NVARCHAR(50)= '',
#RET_MESSAGE AS VARCHAR(8000)='',#RET_ERROR INT=0
SET #ParmDefinition='#SPID INT,#CH2 INT OUTPUT,#CH3 INT OUTPUT'
SET #SQL='UPDATE T
SET CH1=#SPID,#CH2= T.CH2,#CH3= T.CH3
FROM #TAB T WITH(ROWLOCK)
INNER JOIN (
SELECT TOP(1) CH1,CH2,CH3
FROM
#TAB WITH(NOLOCK)
WHERE CH1 IS NULL
ORDER BY CH2 DESC) V ON T.CH2= V.CH2 AND T.CH3= V.CH3'
INSERT INTO #TAB
(CH2 ,CH3 )
SELECT 1,2 UNION ALL
SELECT 2,3 UNION ALL
SELECT 3,4
BEGIN TRY
WHILE EXISTS(SELECT TOP 1 1 FROM #TAB WHERE CH1 IS NULL)
BEGIN
EXECUTE #RET_ERROR = sp_executesql #SQL, #ParmDefinition,#SPID =##SPID, #CH2=#CH2 OUTPUT,#CH3=#CH3 OUTPUT;
SELECT * FROM #TAB
SELECT #CH2,#CH3
END
END TRY
BEGIN CATCH
SET #RET_ERROR=ERROR_NUMBER()
SET #RET_MESSAGE = '#ERROR_NUMBER : ' + CAST(ERROR_NUMBER() AS VARCHAR(255)) + '#ERROR_SEVERITY :' + CAST( ERROR_SEVERITY() AS VARCHAR(255))
+ '#ERROR_STATE :' + CAST(ERROR_STATE() AS VARCHAR(255)) + '#ERROR_LINE :' + CAST( ERROR_LINE() AS VARCHAR(255))
+ '#ERROR_MESSAGE :' + ERROR_MESSAGE() ;
SELECT #RET_ERROR,#RET_MESSAGE;
END CATCH

Resources