Want multiple Rows from 1 Row - sql

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).

Related

SQL Insert iterative number and Id of select Table 1 into table2

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);

MS SQL Server how to instantly insert a 1 to 10 number column to table (virtual column)?

any idea about to instantly add a column for number (1 to 10) for each rows value on existing table?
You can use a CROSS JOIN in concert with an ad-hoc tally table
Example
Select A.*
,B.Code
From YourTable A
Cross Join ( Select Top 10 Code=row_number() Over (Order By (Select NULL)) From master..spt_values n1 ) B
You can generate the rows with a recurisve query, then cross join that with your table.
with codes as (
select 1 code
union all select code + 1 from cte where code < 10
)
select t.*, c.code
from mytable t
cross join codes c
For a small number of rows, I would expect the recusive query to be faster than top 10 against a large table.

Insert unique value multiple times depending on variable column

I have the following columns in my table:
PromotionID | NumberOfCodes
1 10
2 5
I need to insert the PromotionID into a new SQL table a number of times - depending on the value in NumberOfCodes.
So given the above, my result set should read:
PromotionID
1
1
1
1
1
1
1
1
1
1
2
2
2
2
2
You need recursive cte :
with r_cte as (
select t.PromotionID, 1 as start, NumberOfCodes
from table t
union all
select id, start + 1, NumberOfCodes
from r_cte
where start < NumberOfCodes
)
insert into table (PromotionID)
select PromotionID
from r_cte
order by PromotionID;
Default recursion level 100, use query hint option(maxrecursion 0) if you have NumberOfCodes more.
I prefer a tally for such things. Once you start getting to larger row sets, the performance of an rCTe degrades very quickly:
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) --Up to 100 rows. Add more cross joins to N for more rows
SELECT YT.PromotionID
FROM dbo.YourTable YT
JOIN Tally T ON YT.NumberOfCodes >= T.I;
One option uses a recursive common table expression to generate the rows from the source table, that you can then insert in the target table:
with cte as (
select promotion_id, number_of_codes n from sourcetable
union all select promotion_id, n - 1 from mytable where n > 1
)
insert into targettable (promotion_id)
select promotion_id from cte

Generating multiple data with SQL query

I have 2 tables as below
Product_Asset:
PAId Tracks
1 2
2 3
Product_Asset_Resource:
Id PAId TrackNumber
1 1 1
2 1 2
3 2 1
4 2 2
5 2 3
I would like to know if I can generate the data in product_asset_resource table based on product_asset table using TSQL query (without complex cursor etc.)
For example, if the number of tracks in product_asset is 3 then I need to populate 3 rows in product_asset_resource with track numbers as 1,2,3
You can do this with the help of a Tally Table.
WITH E1(N) AS( -- 10 ^ 1 = 10 rows
SELECT 1 FROM(VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))t(N)
),
E2(N) AS(SELECT 1 FROM E1 a CROSS JOIN E1 b), -- 10 ^ 2 = 100 rows
E4(N) AS(SELECT 1 FROM E2 a CROSS JOIN E2 b), -- 10 ^ 4 = 10,000 rows
CteTally(N) AS(
SELECT TOP(SELECT MAX(Tracks) FROM Product_Asset)
ROW_NUMBER() OVER(ORDER BY(SELECT NULL))
FROM E4
)
SELECT
Id = ROW_NUMBER() OVER(ORDER BY pa.PAId, t.N),
pa.PAId,
TrackNumber = t.N
FROM Product_Asset pa
INNER JOIN CteTally t
ON t.N <= pa.Tracks
ONLINE DEMO
Try this,I am not using any Tally Table
declare #Product_Asset table(PAId int,Tracks int)
insert into #Product_Asset values (1 ,2),(2, 3)
;with CTE as
(
select PAId,1 TrackNumber from #Product_Asset
union all
select pa.PAId,TrackNumber+1 from #Product_Asset pa
inner join cte c on pa.PAId=c.PAId
where c.TrackNumber<pa.Tracks
)
select ROW_NUMBER()over(order by paid)id, * from cte
IMHO,Recursive CTE or sub query or using temp table performance depend upon example to example.
I find Recursive CTE more readable and won't use them unless they exhibit performance problem.
I am not convince that Recursive CTE is hidden RBAR.
CTE is just syntax so in theory it is just a subquery
We can take any example to prove that using #Temp table will improve the performance ,that doesn't mean we always use temp table.
Similarly in this example using Tally Table may not improve the performance this do not imply that we should take help of Tally Table at all.

How can I expand out a row into multiple row result set?

I have a table that I'm trying to break out each row into one or more rows based on the second column value. Like this:
table (id, pcs):
ABC 3
DEF 1
GHJ 4
query result (id, pcs_num):
ABC 1
ABC 2
ABC 3
DEF 1
GHJ 1
GHJ 2
GHJ 3
GHJ 4
I'm writing this as a sproc in SQL server 2008. My best solution is to use a cursor and add [pcs] number of rows to a temp table for each row in the table. Is seems like there must be a simpler solution than this that I am missing. Thanks.
You can use a recursive CTE:
;WITH CTE AS
(
SELECT *
FROM YourTable
UNION ALL
SELECT id, pcs-1
FROM CTE
WHERE pcs-1 >= 1
)
SELECT *
FROM CTE
ORDER BY id, pcs
OPTION(MAXRECURSION 0)
Here is a demo for you to try.
Here is my approach. Extremely easy with a Tally Table (A table that only has a column with a value 1 -> X). No need for recursion, and this will be much faster over larger tables.
Notice we are only making a Tally Table of 100 rows, feel free to expand that as large as you'd like. If you get too crazy, you might need another cross join in sys.sysobjects to accomdate. The real query is at the bottom, as you can see it's extremely easy.
SELECT TOP 100
IDENTITY( INT,1,1 ) AS N
INTO #Tally
FROM sys.sysobjects sc1 ,
sys.sysobjects sc2
CREATE TABLE #Test
(
Id char(3),
pcs int
)
INSERT INTO #Test
SELECT 'ABC', 3 UNION ALL
SELECT 'DEF', 1 UNION ALL
SELECT 'GHJ', 4
SELECT #Test.Id, #Tally.N FROM #Tally
JOIN #Test ON #Tally.N <= #Test.pcs
ORDER BY #Test.Id
SELECT
id
,pcs_num
FROM MyTable
CROSS APPLY (
SELECT TOP (pcs)
ROW_NUMBER() OVER(ORDER BY (SELECT 1)) pcs_num
FROM master.dbo.spt_values
) t