Generating Data Using CTE - sql

I need to generate 500 records using CTE, my output table should be something like below
TEST
DESCRIPTION
ID
TEST1
DESC1
1
TEST2
DESC2
2
TEST3
DESC3
3
TEST4
DESC4
4
I struggling with how to create it with cte as it has to be wrapped inside view
i created temp table its working fine but i wasnt able to wrap it inside view
i tried the following code
with cte1 as (
CREATE TABLE #code1(TEST,DESCRIPTION)
declare #TEST int
set #TEST = 1
While #TEST <= 500
Begin
Insert Into #code1(TEST,DESCRIPTION)
values ('TEST' + CAST(#TEST as varchar(100)),'DESC' + CAST(#TEST as varchar(100)))
Print #TEST
Set #TEST = #TEST + 1
End
)
I think I am doing it in the wrong way, can anyone give me any suggestions here.

Your INSERT...SELECT syntax is all off. Start by creating the table normally, then INSERT the rows.
The best way to generate a lot of rows is to use a tally function. Itzik Ben-Gan's cross-join is great, here is a simplified version of it, good for up to 65,536 rows
WITH
L0 AS ( SELECT 1 AS c
FROM (VALUES(1),(1),(1),(1),(1),(1),(1),(1),
(1),(1),(1),(1),(1),(1),(1),(1)) AS D(c) ),
L1 AS ( SELECT 1 AS c FROM L0 AS A CROSS JOIN L0 AS B ),
L2 AS ( SELECT 1 AS c FROM L1 AS A CROSS JOIN L1 AS B ),
Nums AS ( SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS rownum
FROM L2 )
INSERT #code1 (TEST, DESCRIPTION, ID)
SELECT TOP(500)
CONCAT('TEST', rownum) AS TEST,
CONCAT('DESC', rownum) AS DESCRIPTION,
rownum AS ID
FROM Nums;

You can create a stored procedure to achieve a similar result:
SP Code:
DELIMITER $$
CREATE PROCEDURE Proc00()
BEGIN
CREATE TABLE code1 (TEST VARCHAR(20),DESCRIPTION VARCHAR(30),ID INT);
SET #TEST = 1;
WHILE #TEST <= 500 DO
INSERT INTO code1
VALUES (CONCAT('TEST',#TEST),CONCAT('DESC',#TEST),#TEST);
SET #TEST = #TEST + 1;
END WHILE;
SELECT * FROM code1;
END $$
DELIMITER ;
Then let's execute the stored procedure by using CALL() statement:
CALL Proc00();
It returns:
...............

Related

Crash gaps in a SQL string [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I have a select today that returns me the following result:
I make another select that returns a value, 5 for example. I would need to know which numbers are not between the number 1 to the number 5. In my case I would need the following result 2, 4, 5.
I would need help developing this logic.
I have created a sample using NOT EXISTS(), I believe it can help you :
--DROP TABLE #Temp
--GO
CREATE TABLE #Temp
(
NR_VOLUME INT
)
INSERT INTO #Temp
VALUES (1),(3)
--Create Temp table for number List
--DROP TABLE #NumberList
--GO
CREATE TABLE #NumberList
(
Seq INT
)
DECLARE #NumberCheckFrom INT=1
DECLARE #NumberCheckTo INT=100
WHILE #NumberCheckTo>=#NumberCheckFrom
BEGIN
INSERT INTO #NumberList
SELECT #NumberCheckFrom
SET #NumberCheckFrom +=1
END
DECLARE #NumberFrom INT=0
DECLARE #NumberTo INT=5
SELECT *
FROM #NumberList NL
WHERE Seq>=#NumberFrom
AND Seq<=#NumberTo
AND NOT EXISTS (SELECT 1
FROM #Temp T
WHERE NL.Seq = T.NR_VOLUME
)
Build a cte with the values you are looking for. Then get the values that dont exist in your table
with cte (rn) as (select 1 as rn
union all
select rn + 1
from cte
where rn + 1 <= 5)
select cte.rn
from cte
where not exists (select 1 from actualtable where nr_volume = cte.rn)
Your question wasn't clear, but it seems you wanted numbers that weren't present in the range returned by two queries, but fell within that range. For that, you can use a tally table and a few methods to limit the results. Note, you included 5 in your expected results, but this contradicts your question since you didn't include 1 int he expected results.
declare #table1 table (i int)
insert into #table1
values (1),(3)
declare #table2 table (i int)
insert into #table2
values (5)
declare #max int = (select top 1 i from (select max(i) i from #table1 union select max(i) from #table2) x order by i desc)
declare #min int = (select top 1 i from (select min(i) i from #table1 union select min(i) from #table2) x order by i asc)
;WITH
E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
)
select N from cteTally
where
N not in (select * from #table1)
and N not in (select * from #table2)
and N > #min
and N < #max
GO

Inserting individual values into table based on a number

Here is my problem: I have a stored procedure in SQL Server 2012 which should do the following thing.
I will pass an input parameter #Range, and the stored procedure should insert values into a table starting from 0 to #Range-1.
CREATE PROC MyExample
(#Range INT)
AS
BEGIN
// Suppose the value of #Range is 100
// So I should do INSERT into MyTable Values(0,1,2,3,4,5,6,......99)
END
Any idea how to achieve this?
You can use while loop as below:
Declare #Index AS INT=0
WHILE #Index<#Range
BEGIN
INSERT into MyTable Values(#Index)
SET #Index=#Index+1
END
I am thinking your teacher may suspect why you use cte when you just learn a loop
CREATE PROC MyExample
(
#Range INT,
)
AS
BEGIN
;WITH numbers AS
(
SELECT 0 AS Value WHERE #Range >= 0 -- Validate the #Range value too, try 0 or negative values
UNION ALL SELECT Value + 1 FROM numbers WHERE Value + 1 < #Range
)
INSERT INTO MyTable
SELECT * FROM numbers
OPTION (MAXRECURSION 0)
END
And here is a set based approach:
CREATE PROC MyExample
(
#Range INT,
)
AS
BEGIN
INSERT INTO MyTable (Number)
SELECT TOP (#Range) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) - 1
FROM sys.objects s1
CROSS JOIN sys.objects s2
END
(Based on this SO post)
CREATE PROC MyExample
(
#Range INT,
)
AS
BEGIN
declare #RANGE_COUNT int
select #RANGE_COUNT =#Range
//Suppose the value of #Range is 100
while #RANGE_COUNT<>0
begin
//So I should do INSERT into MyTable Values(0,1,2,3,4,5,6,......99)
INSERT into MyTable Values(#Range)
set #RANGE_COUNT = RANGE_COUNT -1
end
END
Using tally table technique:
DECLARE #range INT = 100
SELECT TOP(#range) -1 + ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS rn
FROM
(VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) t1(n) CROSS JOIN --10
(VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) t2(n) CROSS JOIN --100
(VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) t3(n) --1000
--...continue to cover all possible #range values

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.

Populating an empty table with sequential numbers

I have a table which is already truncated (Microsoft SQL 2008). I have to now populate it with sequential numbers up to 50,000 records arbitrary numbers (doesn't mater) up to 7 characters.
Can any one help as to what SQL statement I need to write that will automatically populate the newly empty table with A000001,A0000002,A0000003, etc so that I can sort number the records within the table.
I have approximately 50000 records which I need to sequentially entered and I really don't want to number the column manually via hand editing.
Thanks in advance.
I'd use excel to generate your unique ids using the following:
In A column:
=CONCATENATE($C2, TEXT($B2,"000000"))
In B column put a 1 in the first row and the following code in all subsequent rows:
=SUM($B4 + 1)
In C column:
The letter A
Then just import the excel csv as a table and you'll have all your ids ready to insert into your empty table.
The SQL below loads a table variable up. Just select from it and insert the data into the new table. Certainly not the model of efficiency, but it'll get the job done.
DECLARE #tmp TABLE(
Value NVARCHAR(10)
)
DECLARE #Counter INT=0
DECLARE #Padding NVARCHAR(20)
WHILE #Counter<50000
BEGIN
SET #Counter=#Counter+1
SET #Padding=
CASE LEN(CONVERT(NVARCHAR,#Counter))
WHEN 1 THEN '00000'
WHEN 2 THEN '0000'
WHEN 3 THEN '000'
WHEN 4 THEN '00'
WHEN 5 THEN '0'
ELSE ''
END
INSERT INTO #tmp SELECT 'A' + #Padding + CONVERT(NVARCHAR,#Counter)
END
select * from #tmp
Use Stacked CTE to generate sequential Numbers
;WITH e1(n) AS
(
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
), -- 10
e2(n) AS (SELECT 1 FROM e1 CROSS JOIN e1 AS b), -- 10*10
e3(n) AS (SELECT 1 FROM e2 CROSS JOIN e2 AS b), -- 100*100
e4(n) AS (SELECT 1 FROM e3 CROSS JOIN (SELECT TOP 5 n FROM e1) AS b) -- 5*10000
SELECT n = 'A'+right('000000'+
convert(varchar(20),ROW_NUMBER() OVER (ORDER BY n)),7)
FROM e4 ORDER BY n;
Check here for more methods to generate sequential numbers with performance analysis
Use a table with an identity column and populate it. Then update that table to set the alpha value you need as follows:
create table MyTable (
ID int not null identity(1,1),
Alpha varchar(30)
)
truncate table MyTable
begin tran -- makes it run much faster
declare #i int
select #i = 1
while #i < 1000000
begin
insert into MyTable (Alpha) values ('')
select #i = #i + 1
end
commit
update MyTable set Alpha = 'A' + replicate('0', 6 - len(cast(ID as varchar(30)))) + cast(ID as varchar(30))

finding the missing values in a Sequence

Table1 is as follows :
Col1
1
2
3
4
6
7
8
9
10
13
14
As shown above the col1 has the sequence of values but for some reason the user did not insert 5, 11 and so on. How to find out the missing values in a sequence. Here the sequence is 1 to 14 and the missing values are 5,11. Please help me.
As was said in other answers, the best choice is to do a join with a real sequence table. You can create one using a recursive CTE:
DECLARE #MaxNumber INT
SELECT #MaxNumber = MAX(Col1) FROM YourTable;
WITH CTE AS
(
SELECT 1 Col1
UNION ALL
SELECT Col1+1
FROM CTE
WHERE Col1+1 <= #MaxNumber
)
SELECT A.Col1
FROM CTE A
LEFT JOIN YourTable B
ON A.Col1 = B.Col1
WHERE B.Col1 IS NULL
OPTION(MAXRECURSION 0)
This will work for numbers 0 - 2000 for large numbers you just need to cross join the original result set.
with temp as (
select distinct number
from master..spt_Values
where number between 0 and 2000
)
select * from
temp t
left join your_table y on y.col1 = t.number
where y.col1 is null
alternatively using cross join
This will work for billions obviously slower
WITH
L0 AS(SELECT 1 AS c UNION ALL SELECT 1),
L1 AS(SELECT 1 AS c FROM L0 AS A CROSS JOIN L0 AS B),
L2 AS(SELECT 1 AS c FROM L1 AS A CROSS JOIN L1 AS B),
L3 AS(SELECT 1 AS c FROM L2 AS A CROSS JOIN L2 AS B),
L4 AS(SELECT 1 AS c FROM L3 AS A CROSS JOIN L3 AS B),
L5 AS(SELECT 1 AS c FROM L4 AS A CROSS JOIN L4 AS B),
Nums AS(SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS n FROM L5)
select * from
l5 t
left join your_table y on y.col1 = t.n
where y.col1 is null
This seems to pretty much be a duplication of
SQL query to find Missing sequence numbers
There's a suggestions this will work:
SELECT l.id + 1 as start
FROM Table1 as l
LEFT JOIN Table1 as r on l.id + 1 = r.id
WHERE r.id IS NULL
Otherwise you can left join on your table with a sequence table. From the above question, you can look at http://www.projectdmx.com/tsql/tblnumbers.aspx to get some ideas on how to generate a suitable sequence table, and the join will be something like
SELECT #sequence.value
FROM #sequence
LEFT JOIN Table1 ON #sequence.value = Table1.value
WHERE Table1.value IS NULL
Side-note to all recursive CTE suggestions. The recursive CTE increases time linear to the number of rows. Using a tally table or cross-join is much better to use...
This would work:
-- data table
CREATE TABLE #data (
value INT
)
INSERT #data VALUES (1)
INSERT #data VALUES (2)
INSERT #data VALUES (3)
INSERT #data VALUES (4)
INSERT #data VALUES (6)
INSERT #data VALUES (7)
INSERT #data VALUES (8)
INSERT #data VALUES (9)
INSERT #data VALUES (10)
INSERT #data VALUES (13)
INSERT #data VALUES (14)
-- normally i have a tally table already for stuff like this but I'll
-- create one temporary here.
CREATE TABLE #tmp_tally (
n INT
)
DECLARE #n INT
SET #n = 1
WHILE #n < 14
BEGIN
INSERT #tmp_tally VALUES (#n)
SET #n = #n + 1
END
SELECT
T.n,
CASE WHEN #data.value IS NULL THEN 'Missing' ELSE 'Not Missing' END
FROM
#tmp_tally T
LEFT JOIN #data ON
T.n = #data.value
WHERE
T.n <= (SELECT MAX(value) FROM #data) -- max of what you want to check against which is 14 in your example
DROP TABLE #data
DROP TABLE #tmp_tally
Try this:
declare #min int
declare #max int
select #min = min(field_ID), #max = max(field_ID) from [Table]
create table #tmp (Field_No int)
while #min <= #max
begin
if not exists (select * from [Table] where field_ID = #min)
insert into #tmp (seq_field) values (#min)
set #min = #min + 1
end
select * from #tmp
drop table #tmp
With the above script you will get missing values in "ID" column from #tmp table.
Hope this will help you!!
I would do a subquery in the same table, to see if another number exist for the current number-1, and if there is not one, you know that a number was skipped. You can do the +1 of this as well.
select
nt.numb,
CASE
(select COUNT(*) from table where numb=nt.numb-1)=0 THEN 'skipped' ELSE 'not skipped'
from
numbertable nt