Get top number of rows anyway - sql

My requirement is like select top 5 rows from sql, if it contains only 2 rows then by default it shows some text say 'no data' in remaining 3 rows. Same for all conditions.
For i.e. Select top 5 rows, but it contains only 3 rows then query will return
Row1
Row2
Row3
No Data
No Data

Please try:
select top 5 Col
from(
select 0 srt, Col from YourTable
union all
select 1 srt, 'No Data' Col union all
select 1 srt, 'No Data' Col union all
select 1 srt, 'No Data' Col union all
select 1 srt, 'No Data' Col union all
select 1 srt, 'No Data' Col
)x
order by srt

this will be much more dynamic
declare #t TABLE (id int,TerminalID varchar(15))
declare #top int
set #top = 5
declare #c int --Holds Total
set #c = 0
while (#c < #top) begin
insert into #t (id, TerminalID) values (#c, 'No Data')
set #c = #c + 1
end
select top 5 * from
(
select top 5 TerminalID from AccessLog-- [where colo0 = ???]
union all
select TerminalID from #t
) x

/* assuming the column width is 8 characters and datatype is varchar */
DECLARE #NoDataTable AS TABLE(column1 VARCHAR(8))
DECLARE #i AS INT
SET #i = 0
WHILE(#i<5)
BEGIN
insert into #NoDataTable (column1)
values('No Data');
set #i = #i+1
end
select top 5 *
from
(
select column1 from TestTable
union all
select column1 from #NoDataTable
) as T

WITH cte AS
(
SELECT YourColumn FROM YourTable
UNION ALL
SELECT TOP 5 NULL FROM YourTable
)
SELECT TOP 5 COALESCE(YourColumn, 'No Data')
FROM cte

Related

SQL - populate new column according to data in row above

I need to populate a new column in a table known as RowType, where if the ID column contains the same ID value as the one above RowType is populated with 'D', if the value is new then RowType is populate with 'H', how would the SQL code look to be able to do this?
I.e should look something like below:
RowType (to be populated), ID (already there)
H, 1
D, 1
D, 1
H, 2
D, 2
H, 3
D, 3
D, 3
Thanks
You can use Row_Number and case
select *, RowType = case when Row_Number() over (partition by id order by id) = 1 then 'H' else 'D' End from #yourid
Your input table:
create table #yourId (id int)
insert into #yourid (id) values
(1)
,(1)
,(1)
,(2)
,(2)
,(3)
,(3)
,(3)
Use ROW_NUMER concept :
CREATE TABLE #table(Id INT)
INSERT INTO #table(Id)
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 2 UNION ALL
SELECT 2 UNION ALL
SELECT 3 UNION ALL
SELECT 3 UNION ALL
SELECT 3
SELECT CASE WHEN RowType = 1 THEN 'H' ELSE 'D' END RowType , Id
FROM
(
SELECT ROW_NUMBER() OVER (PARTITION BY Id ORDER BY id) RowType , Id
FROM #table
) A
Please try...
UPDATE tableName
SET RowType = CASE
WHEN ( ID = LAG( ID ) OVER ( ORDER BY ID ) ) THEN 'D'
ELSE 'H'
END
If you have any questions or comments, then please feel free to post a Comment accordingly.
Further Reading
https://learn.microsoft.com/en-us/sql/t-sql/functions/lag-transact-sql (for information on LAG()).
It may not be the best solution, however it can point you somewhere, and it works.
Go through the code carfuly and make sure you understand this.
create table yourTable (RowType char, id int)
insert into yourTable (RowType, id) values
('',1)
,('',1)
,('',1)
,('',2)
,('',2)
,('',3)
,('',3)
,('',3)
select
row_number() over (order by id) as rowNumber,
RowType,
id
into #tempTable
from yourTable
declare #maxRow int = (select max(rowNumber) from #tempTable)
declare #currentRow int = 1
while (#currentRow <= #maxRow)
begin
if (#currentRow = 1)
begin
update #tempTable
set RowType = 'H'
where rowNumber = #currentRow
end
else
begin
if (select id from #tempTable where rowNumber = #currentRow) = (select id from #tempTable where rowNumber = #currentRow - 1)
begin
update #tempTable
set RowType = 'D'
where rowNumber = #currentRow
end
else
begin
update #tempTable
set RowType = 'H'
where rowNumber = #currentRow
end
end
set #currentRow = #currentRow +1
end
-- update data in actual table, you can do below if only those two columns exist in table !!!
delete from yourTable
-- insert into table from updated temp table
insert into yourTable
select RowType, ID
from #tempTable
select * from yourTable
select * from #tempTable
-- drop temp table
drop table #tempTable

In SQL , how to build a loop that copies a row number of times

could someone please help? My starting table looks like this with 2 fields:
Name Counter
dave 2
Joe 3
I want my result to look like this:
Name Counter
dave 1
dave 2
joe 1
joe 2
joe 3
Essentially creating n number of records base on the counter and starts at 1. I tried to do a loop using counter as a variable, but the code just runs nonstop.. could someone help?
A procedural SQL Server solution:
declare #input table
(
name nvarchar(100)
,wantedrows int
,processed bit
,id uniqueidentifier
);
declare #output table
(
name nvarchar(100)
,rownum int
);
insert into #input
select 'Dave',3,0,newid()
union
select 'Joe',2,0,newid();
while exists(select * from #input where processed = 0)
begin
declare #currentid uniqueidentifier = (select top 1 id from #input where processed = 0);
declare #currentwantedrows int = (select wantedrows from #input where id = #currentid);
declare #i int = 0;
while #i < #currentwantedrows
begin
insert into #output
select name,#i+1
from #input
where id = #currentid;
set #i = #i + 1;
end;
update #input set processed = 1 where id = #currentid;
end
select name,wantedrows from #input;
select * from #output;
You can use a number-table or following trick using a system view to build a sequence:
WITH Nums AS
(
SELECT n = ROW_NUMBER() OVER (ORDER BY [object_id])
FROM sys.all_objects
)
SELECT Name, Counter = n
FROM Nums n CROSS JOIN Table1 t1
WHERE n BETWEEN 1 AND Counter
ORDER BY Name, Counter;
Demo
This view has only about 2000 rows, so if you need more you could use a number-table.
http://sqlperformance.com/2013/01/t-sql-queries/generate-a-set-1
( presuming SQL-Server )
Is a hundred copies enough?
create table #c (num)
insert into #c (num)
select 0 union
select 1 union
select 2 union
select 3 union
select 4 union
select 5 union
select 6 union
select 7 union
select 8 union
select 9
select T.Name, c1.num * 10 + c0.num + 1
from T, #c c1, #c c0
where c1.num * 10 + c0.num < T.Counter
drop table #c
You didn't say which version of Sybase. The old ones I've worked on didn't allow derived tables so I had to throw the values into a temp table. But you can see how to extend the idea. This may not be the best approach if this is something you need to do more than once though.

Select non-existing rows

Let say I have a table:
ColumnA ColumnB
---------------------------------
1 10.75
4 1234.30
6 2000.99
How can I write a SELECT query that will result in the following:
ColumnA ColumnB
---------------------------------
1 10.75
2 0.00
3 0.00
4 1234.30
5 0.00
6 2000.99
You can use a CTE to create a list of numbers from 1 to the maximum value in your table:
; with numbers as
(
select max(ColumnA) as nr
from YourTable
union all
select nr - 1
from numbers
where nr > 1
)
select nr.nr as ColumnA
, yt.ColumnB
from numbers nr
left join
YourTable yt
on nr.nr = yt.ColumnA
order by
nr.nr
option (maxrecursion 0)
See it working at SQL Fiddle.
Please try:
declare #min int, #max int
select #min=MIN(ColumnA), #max=MAX(ColumnA) from tbl
select
distinct number ColumnA,
isnull(b.ColumnB, 0) ColumnB
from
master.dbo.spt_values a left join tbl b on a.number=b.ColumnA
where number between #min and #max
Create a TallyTable (or NumbersTable) - see this question: What is the best way to create and populate a numbers table?
With that table create an insert statement:
INSERT INTO YourTable (ColumnA, ColumnB)
SELECT Number FROM NumberTable
WHERE
NOT EXISTS (SELECT 1 FROM YourTable WHERE NumberTable.Number = YourTable.ColumnA)
-- Adjust this value or calculate it with a query to the maximum of the source table
AND NumberTable.Number < 230130
DECLARE #t TABLE (ID INT,Val DECIMAL(10,2))
INSERT INTO #t (ID,Val) VALUES (1,10.75)
INSERT INTO #t (ID,Val) VALUES (4,6.75)
INSERT INTO #t (ID,Val) VALUES (7,4.75)
declare #MinNo int
declare #MaxNo int
declare #IncrementStep int
set #MinNo = 1
set #MaxNo = 10
set #IncrementStep = 1
;with C as
(
select #MinNo as Num
union all
select Num + #IncrementStep
from C
where Num < #MaxNo
)
select Num,
CASE WHEN Val IS NOT NULL THEN Val ELSE 0.00 END AS NUMBER
from C
LEFT JOIN #t t
ON t.ID = c.Num
You could use a number-table or following trick to generate a sequence which you can LEFT OUTER JOIN with your table. I assume you want to determine the boundaries dynamically:
WITH Seq AS
(
SELECT TOP ((SELECT Max(ColumnA)FROM Table1) - (SELECT Min(ColumnA) FROM Table1) + 1)
Num = (SELECT Min(ColumnA) FROM Table1)+ Row_number() OVER (ORDER BY [object_id]) -1
FROM sys.all_objects)
SELECT ColumnA = Seq.Num,
ColumnB = COALESCE(t.ColumnB ,0.00)
FROM Seq
LEFT OUTER JOIN Table1 t
ON Seq.Num = t.ColumnA
Demo with your sample.
Worth reading: http://www.sqlperformance.com/2013/01/t-sql-queries/generate-a-set-1
I have my collect of table functions like these.
create function dbo.GetNumbers(#Start int, #End int)
returns #Items table
(
Item int
)
as
begin
while (#Start <= #End)
begin
insert into #Items
values (#Start)
set #Start = #Start + 1
end
return
end
Then I can use it to left join to my data table and every value will be there.
declare #min int, #max int
set #min = 10
set #max = 20
select gn.Item
from dbo.GetNumbers(#min, #max) gn
I have similar table functions for date ranges, times, timezones, etc.

How do I check whether data is there or not in more than one sql table in one script?

I have more than 3 sql tables.
now i'm trying to select count(*) from all tables but how can i do this?.
I want to know whether data is present in all tables or not
I need to check the row count from previous business day ~15% for any table and it sends an email alert
I tried like following please help me to complete
PROCEDURE [dbo].[SendEmail_WSOTableDataAlert]
AS
BEGIN
declare #err int
IF NOT EXISTS (select 1 from T1) OR
NOT EXISTS (select 1 from T2)
BEGIN
set #error=1
END
//here i need to show which table is having empty data how can i do this please help
SET #tableHTML = #tableHTML + +
'</TABLE>' + #EmailFooter;
#error =1
then
send mail
END
Select
case when count(*) = 0 then
'No rows'
else
'Has rows'
end
FROM
(
Select * from #table1
UNION ALL
Select * from #table2
UNION ALL
Select * from #table3
) t
UPDATE
This makes sure all of then have at least one row and fail if any of them does not have record
Select
case when count(*) = 0 then
'No rows'
else
'Has rows'
end
FROM
(
Select top 1 1 found from #table1
intersect
Select top 1 1 found from #table2
intersect
Select top 1 1 found from #table3
) t
You can try multiplying the flags indicating zero counts together. If any of them is zero, the result will be zero.
select (case when (select count(*) from table1)=0 then 0 else 1 end
*case when (select count(*) from table2)=0 then 0 else 1 end
*case when (select count(*) from table3)=0 then 0 else 1 end) as no_zeros
If you would like to know which table has all zeros, you could transform the query as follows:
select (case when (select count(*) from table1)=0 then 1 else 0 end
+case when (select count(*) from table2)=0 then 2 else 0 end
+case when (select count(*) from table3)=0 then 4 else 0 end
+case when (select count(*) from table4)=0 then 8 else 0 end) as no_zeros
Use powers of two (1, 2, 4, 8, 16, 32, and so on) as your flags. Ones 1 in the binary representation of the result will tell you which tables have no records.
(select count() from table1 )
union all
(select count() from table2 )
union all
(select count(*) from table3 )
And then loop through the rows of the result
declare #count1 int
select #count1 = count(*)
from table1
declare #count2 int
select #count2 = count(*)
from table2
declare #count3 int
select #count3 = count(*)
from table3
if (#count1 + #count2 + #count3 = 0)
--do something
else
--do something else
You can use the EXISTS keyword to efficiently check if there is any data in a table.
IF NOT EXISTS (SELECT 1 FROM Table1) OR NOT EXISTS (SELECT 1 FROM Table2) OR NOT EXISTS (SELECT 1 FROM Table3)
BEGIN
/* do something */
END

Add null's for numerics using CTE in Sql Server 2005

I have some data as below
ID Data
1 a
1 2
1 b
1 1
2 d
2 3
2 r
Desired Output
ID Data
1 a
1 NULL
1 NULL
1 b
1 NULL
2 d
2 NULL
2 NULL
2 NULL
2 r
What the output is , for the numerics it is replaced with those many null values. E.g. for a numeric value of 2 , it will be 2 null values.
The ddl is as under
Declare #t table(ID int, data varchar(10))
Insert into #t
Select 1, 'a' union all select 1, '2' union all select 1, 'b' union all select 1, '1' union all select 2,'d' union all
select 2,'3' union all select 2, 'r'
select * from #t
Please give a CTE based solution. I already have the procedural approach but I need to have a feel of CTE based solution.
Solution I am using at present
CREATE FUNCTION [dbo].[SPLIT] (
#str_in VARCHAR(8000)
)
RETURNS #strtable TABLE (id int identity(1,1), strval VARCHAR(8000))
AS
BEGIN
DECLARE #tmpStr VARCHAR(8000), #tmpChr VARCHAR(5), #ind INT = 1, #nullcnt INT = 0
SELECT #tmpStr = #str_in
WHILE LEN(#tmpStr) >= #ind
BEGIN
SET #tmpChr = SUBSTRING(#tmpStr,#ind,1)
IF ISNUMERIC(#tmpChr) = 0
INSERT INTO #strtable SELECT #tmpChr
ELSE
WHILE #nullcnt < #tmpChr
BEGIN
INSERT INTO #strtable SELECT NULL
SET #nullcnt = #nullcnt + 1
END
SELECT #ind = #ind + 1, #nullcnt = 0
END
RETURN
END
GO
Invocation
SELECT * from dbo.SPLIT('abc2e3g')
I donot want to do it using function but a CTE solution.
Reason: I am learning CTE and trying to solve problems using it. Trying to come out of procedural/rBar approach.
Thanks
Setup:
declare #t table(UniqueID int identity(1,1), ID int, data varchar(10))
insert into #t
select 1, 'a' union all
select 1, '2' union all
select 1, 'b' union all
select 1, '1' union all
select 2, 'd' union all
select 2, '3' union all
select 2, 'r'
Query:
;with cte
as
(
select UniqueId, id, data, case when isnumeric(data) = 1 then cast(data as int) end Level
from #t
union all
select UniqueId, id, null, Level - 1
from cte
where Level > 0
)
select id, data
from cte
where Level is null or data is null
order by UniqueID, Level
Output:
id data
----------- ----------
1 a
1 NULL
1 NULL
1 b
1 NULL
2 d
2 NULL
2 NULL
2 NULL
2 r
I added UniqueId as there should be some kind of field that specifies order in the original table.
If you have a numbers table, this becomes quite simple.
;WITH Nbrs ( Number ) AS (
SELECT 1 UNION ALL
SELECT 1 + Number FROM Nbrs WHERE Number < 8000 )
SELECT
M.UniqueID, M.ID, Data
FROM
#t M
WHERE
ISNUMERIC(M.Data) = 0
UNION ALL
SELECT
M.UniqueID, M.ID, NULL
FROM
#t M
JOIN --the <= JOIN gives us (M.Data) rows
Nbrs N ON N.Number <= CASE WHEN ISNUMERIC(M.Data) = 1 THEN M.Data ELSE NULL END
ORDER BY
UniqueID
OPTION (MAXRECURSION 0)
Edit: JOIN was wrong way around. Oops.
Numbers CTE taken from here