I have a numeric sequence of items that I need to insert into an entire table [Table 2].
Table 2 is made of items related to Table 1.
I need to add a set number of elements (A SET of ITEMS) into Table 2 , each set for each ID of Table 1. ID 1 in Table 1 will have roughly 100 elements referenced in Table 2 items 1-99, 100-199 would be associated with ID 2.
That might not be as clear as the pseudo code below. That is what I am trying to achieve.
Pseudo Code is
For Each Record in Select All Records from Table 1 ***(this is where I need help to know how to do)***
SET #cnt=1;
While (#cnt <100)
Insert Into Table 2, PK=#cnt, Name_#Cnt, Record.Id
SET #cnt =#cnt+1;
End
Maybe there is an easier way - by creating a temp table and insert on Innerjoin ??
I do not know I am rustier than I would like to be..
On the latest version of SQL Server, this is simply a case of using GENERATE_SERIES:
INSERT INTO dbo.Table2 (<Column List>)
SELECT <T1 Column List>,
GS.Value
FROM dbo.Table1 T1
CROSS APPLY GENERATE_SERIES(1,100,1);
On older versions, then you'll want to use a Tally. Ideally you'll want to create a function, but you can do this inline:
WITH N AS (
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS (
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I
FROM N N1, N N2) --100 rows
INSERT INTO dbo.Table2 (<Column List>)
SELECT <T1 Column List>,
T.I
FROM dbo.Table1 T1
CROSS JOIN Tally T;
If you wanted to create a function, then the one I use is the following:
CREATE FUNCTION fn.Tally (#End bigint, #StartAtOne bit)
RETURNS table
AS RETURN
WITH N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
SELECT 0 AS I
WHERE #StartAtOne = 0
UNION ALL
SELECT TOP (#End)
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I
FROM N N1, N N2, N N3, N N4, N N5, N N6, N N7, N N8)
SELECT I
FROM Tally;
Then you could use that in your INSERT in a similar way to GENERATE_SERIES:
INSERT INTO dbo.Table2 (<Column List>)
SELECT <T1 Column List>,
T.I
FROM dbo.Table1 T1
CROSS APPLY fn.Tally(100,1);
Related
I have a table in a SQL Server like this (example):
ID
ARTICLE
ARTTEXT
COUNT
1
123456
Test1
5
2
324644
blabla
1
3
765456
nanana
12
Now these items are to be labelled. I.e. each copy needs a label. I then do this via the SSRS.
So I need from ID 1 5 labels, ID 2 1, ID 3 12.
Now the question is what does the select look like to get 5 rows from ID 1, 1 row from ID 2 and 12 rows from ID 3.
I guess a CTE, but it's not clear to me how to get x times the records
I look forward to your ideas.
I would use a Tally over the (far slower) rCTE solution. I use an inline tally here. If you need more than 100 rows, simply add more cross joins to N in the CTE defined as Tally (each cross join increases the maximum number of rows by a factor or 10).
CREATE TABLE dbo.YourTable (ID int,
Article int,
Arttext varchar(15),
[Count] int);
INSERT INTO dbo.YourTable
VALUES(1,123456,'Test1',5),
(2,324644,'blabla',1),
(3,765456,'nanana',12);
GO
WITH N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
SELECT TOP (SELECT MAX([Count]) FROM dbo.YourTable)
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I
FROM N N1, N N2) --100 rows, add more cross joins for more rows
SELECT YT.ID,
YT.Article,
YT.Arttext,
T.I AS [Count]
FROM dbo.YourTable YT
JOIN Tally T ON YT.[Count] >= T.I
ORDER BY YT.ID,
T.I;
GO
DROP TABLE dbo.YourTable;
If I understand correctly, you want to multiply the number of rows based on count. One method uses a recursive CTE:
with cte as (
select id, article, arttext, count
from t
union all
select id, article, arttext, count - 1
from cte
where count > 1
)
select id, article, arttext
from t;
If the count exceeds 100, then you want option (maxrecursion 0).
I need to select random rows from a table for test data. There may be times I need more rows of test data than there are records in the table. Duplicates are okay. How do I structure my select so that I can get duplicate rows?
CREATE TABLE [Northwind].[dbo].[Persons]
(PersonID int, LastName varchar(255))
INSERT INTO [Northwind].[dbo].[Persons]
VALUES
(1, 'Smith'),
(2, 'Jones'),
(3, 'Washington')
SELECT TOP 5 *
FROM [Northwind].[dbo].[Persons]
ORDER BY NEWID()
How do I get the Select statement to give me five records in random order, with repeats? Currently, it only returns three in random order.
I'd like to be able to extend this to get 100 rows or 1000 rows or however many I need.
Use a recursive CTE to union enough rows so that they are larger than what you desire. Then select from that as you have done before.
declare
#desired int = 5,
#actual int = (select count(*) from persons);
with
persons as (
select personId,
lastName,
batch = 0
from Persons
union all
select personId,
lastName,
batch = batch + 1
from persons
where (batch + 1) * #actual < #desired
)
select
top (#desired) personId, lastName
from persons
order by newid()
As mentioned. You could instead us a tally table and then get the random rows;
WITH N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL)))N(N)),
Tally AS(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I
FROM N N1, N N2, N N3, N N4) --Repeat for more
SELECT TOP 500 YT.*
FROM Tally T
CROSS JOIN YourTable YT
ORDER BY NEWID();
I was thinking of how you would solve this without ordering all the records, especially multiple times.
One method is to generate random numbers and to use those for looking up values in your data:
with n as (
select rand(checksum(newid())) as r, 1 as n
union all
select rand(checksum(newid())) as r, n + 1
from n
where n < 10
),
tt as (
select t.*, lag(tile_end, 1, 0) over (order by tile_end) as tile_start
from (select t.*, row_number() over (order by newid()) * 1.0 / count(*) over () as tile_end
from t
) t
)
select tt.*, n.r, (select count(*) from n)
from n left join
tt
on n.r >= tt.tile_start and n.r < tt.tile_end;
Here is a db<>fiddle. The row_number() does not need to use order by newid(). It can order by a key that has an index -- which makes that component much more efficient.
For more than 100 rows, you will need OPTION (MAXRECURSION 0).
I added a temp results table and looped through the query and pushed the results into the temp table.
declare #results table(
SSN varchar(10),
Cusip varchar(10),
...
EndBillingDate varchar(10))
DECLARE #cnt INT = 0;
WHILE #cnt < #trades
BEGIN
INSERT INTO #results
Select ...
set #cnt = #cnt + 10
END
select * from #results
I have a table that ranges from 1-100000 but there are gaps in the ids where items have been deleted. I want a SQL statement that will return me a list of all unused ids in the table so I can get a list of items that were deleted.
I want the list but randomizing the list is a bonus actually. I think it can be done with a rand function...
I'd like to keep it ansi SQL if possible to maintain portability but if not, then that's ok...
You can do this with a use of Tally Table.
Create our sample data.
CREATE TABLE #ids(
id INT IDENTITY(1, 1)
)
SET IDENTITY_INSERT #ids ON
--Insert 100,000 rows
INSERT INTO #ids(id)
SELECT TOP 100000 ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
FROM sys.columns a
CROSS JOIN sys.columns b
SET IDENTITY_INSERT #ids OFF;
-- Randomly delete 1000 rows
WITH cte AS(
SELECT TOP 1000 id
FROM #ids
ORDER BY NEWID()
)
DELETE FROM cte
Using a Tally Table, create a list of numbers from 1 - 100,000. Then use NOT EXISTS to get the unused ids. To randomize the list, add on ORDER BY NEWID() clause.
DECLARE #min INT = 1,
#max INT = 100000
;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
),
E2(N) AS(SELECT 1 FROM E1 a CROSS JOIN E1 b),
E4(N) AS(SELECT 1 FROM E2 a CROSS JOIN E2 b),
E8(N) AS(SELECT 1 FROM E4 a CROSS JOIN E4 b),
Tally(N) AS(
SELECT TOP(#max) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) FROM E8
)
SELECT N
FROM Tally t
WHERE NOT EXISTS(
SELECT 1 FROM #ids WHERE id = t.N
)
ORDER BY NEWID() -- Sorts the result in a random order
There are 999 rows and they have distinct 0-1000 number with one number missing in it. How to find that number using a SQL query?
Use something like this:
SELECT Min(ID) As firstMissedID
FROM (
SELECT *, ROW_NUMBER() OVER (ORDER BY ID) rn
FROM std) dt
WHERE rn < ID
I am assuming that number column will have only numbers from 0 to 1000.
declare #minnumber int
declare #missingnumber int
select #minnumber=min(number) from Test
if(#minnumber=0)
begin
--500500 is the sum of 1 to 1000 number
select #missingnumber=500500-sum(number) from Test
end
else
begin
set #missingnumber=0
end
Use a tally table to get the list of 1000 rows then use LEFT OUTER JOIN or NOT EXISTS to find the missing Number
WITH Tally (n) AS
(
-- 1000 rows
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) a(n)
CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) b(n)
CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) c(n)
)
SELECT Min(n)
FROM Tally T
LEFT OUTER JOIN YOURTABLE Y
ON T.N = Y.MISSING_NUM_COLUMN
WHERE Y.MISSING_NUM_COLUMN IS NULL
If you want to find the list of missing Numbers then remove the MIN operator from the last select query.
SELECT Missing_Numbers = n
FROM Tally T
LEFT OUTER JOIN YOURTABLE Y
ON T.N = Y.MISSING_NUM_COLUMN
WHERE Y.MISSING_NUM_COLUMN IS NULL
not sure if this is the best approach but it'll work.
Create a temp table with a column to hold integer values
=#temptbl1
fill the table with values 1 to 1000 then run this query which will return an entry only if it's not contained in your datatable.
select value from #temptable1 where value not in (select Othervalue from othertable)
the select statement will return all missing values.
I have a table (TableA) with an integer column(ColumnA) and there is data already in the table. Need to write a select statement to insert into this table with the integer column having random values within 5000. This value should not already be in columnA of TableA
Insert into TableA (columnA,<collist....>)
SELECT <newColId> ,<collist....> from TableB <where clause>
you can create a helper numbers table for this:
-- create helper numbers table, faster than online recursive CTE
-- can use master..spt_values, but actually numbers table will be useful
-- for other tasks too
create table numbers (n int primary key)
;with cte_numbers as (
select 1 as n
union all
select n + 1 from cte_numbers where n < 5000
)
insert into numbers
select n
from cte_numbers
option (maxrecursion 0);
and then insert some numbers you don't have in TableA (using join on row_number() so you can insert multiple rows at once):
;with cte_n as (
select n.n, row_number() over(order by newid()) as rn
from numbers as n
where not exists (select * from tableA as t where t.columnA = n.n)
), cte_b as (
select
columnB, row_number() over(order by newid()) as rn
from tableB
)
insert into TableA(columnA, columnB)
select n.n, b.ColumnB
from cte_b as b
inner join cte_n as n on n.rn = b.rn
If you're sure that there could be only one row from TableB which will be inserted, you can
use this query
insert into TableA(columnA, columnB)
select
a.n, b.columnB
from tableB as b
outer apply (
select top 1 n.n
from numbers as n
where not exists (select * from tableA as t where t.columnA = n.n)
order by newid()
) as a
Note it's better to have index on ColumnA column to check existence faster.
sql fiddle demo