How to Split one row data to many rows - sql

I need to insert the following Data in table A and to make trigger for the inserted date to split in many rows in table B depend on the data in table A
For Example
Table A have the following Data :
Name Start_Date Totals No_Payment Diff_Date
Dave 1/10/17 10000 5 7
the Data to split into Table A for 5 Row depend on No_Payment column and add 7 days to Start_Date based on Diff_Date column .
Thank you

Not sure about your requirement, re explain it.
declare #t table(Name varchar(50), Start_Date date,Totals int, No_Payment int,Diff_Date int)
insert into #t values ('Dave','1/10/17', 10000 , 5, 7)
create table #num(num int)
insert into #num
select ROW_NUMBER()over(order by number) from master..spt_values
--select * from #num
SELECT *
,NewStartDate
,DATEADD(day, t.Diff_Date, NewStartDate) RequireStartDate
FROM #t t
CROSS APPLY (
SELECT DATEADD(day, num, t.Start_Date) NewStartDate
FROM #num
WHERE num <= t.No_Payment
) c
drop table #num

Here is the simplest solution.
declare #t table (Name varchar(10), Start_Date datetime,Totals int,No_Payment int,Diff_Date int)
insert #t
values ('Dave','1/10/17',10000,5,7),
('JOHN','2/10/17',10001,2,5),
('Fotos','3/10/17',10002,3,4),
('Manchi','7/10/17',10003,4,6)
select * from #t;
--Insert into <YOUR TABLE>
select t.Name
, DATEADD(day,t.Diff_Date, t.Start_Date) as Start_Date
,t.Totals
,t.No_Payment
,t.Diff_Date
from #t t
join master..spt_values n
on n.type = 'P'
and n.number < convert(int,No_Payment,1)
It's working in SQLServer-2014.

Related

Find missing numbers in a sequence in MS SQL

Say i have a table with an integer column Id. I need to find the missing numbers in a sequence with a maximum returned amount.
If the table is empty and i'm asking for 10, it should return the numbers 1-10.
If the table has 1-5 and i'm asking for 10, it should return the numbers 6,7,8,9,10,11,12,13,14,15.
If the table has 1,2,4,6,9 and im asking for 10, it should return the numbers 3,5,7,8,10,11,12,13,14,15
How can i achive this in one single query using MS SQL?
Thanks in advance!
Try this:
If you need to get more numbers, just increase the WHERE Number<=100.
DECLARE #Tab1 TABLE (ID INT)
INSERT INTO #Tab1 VALUES(1)
INSERT INTO #Tab1 VALUES(3)
INSERT INTO #Tab1 VALUES(5)
INSERT INTO #Tab1 VALUES(7)
INSERT INTO #Tab1 VALUES(9)
;WITH CTE AS
(
SELECT 1 AS Number
UNION ALL
SELECT Number + 1 FROM CTE
WHERE Number<=100
)
SELECT TOP 5 *
FROM CTE
WHERE Number NOT IN(SELECT ID FROM #Tab1)
ORDER BY Number
OPTION (maxrecursion 0);
Existing values:
Number
1
3
5
7
9
OutPut:
Number
2
4
6
8
10
Hope this helps you.
This should work
There are also a system table with numbers
declare #T table (i int primary key);
insert into #T values (1), (2), (4), (6), (9);
declare #count int = 10;
declare #size int = (select count(*) from #T);
with cte as
( select 1 as num
union all
select num + 1
from cte
where num + 1 <= (#count + #size)
)
select top (#count) cte.num
from cte
left join #T t
on t.i = cte.num
where t.i is null
order by cte.num
option ( MaxRecursion 0 );

Sum of last 6 rows for same day as today in SQL Server

I need to calculate sum of past six rows for same day for given id.
Have a look at the sample data and result expected..
create table #t (id int, a datetime, dy varchar(10), t int);
insert into #t values
(1,'2017-01-03','Tuesday',7),
(1,'2017-01-10','Tuesday',5),
(1,'2017-01-17','Tuesday',5),
(1,'2017-01-24','Tuesday',2),
(1,'2017-01-31','Tuesday',6),
(1,'2017-02-07','Tuesday',4),
(1,'2017-02-14','Tuesday',5),
(1,'2017-02-21','Monday',2),
(1,'2017-02-28','Monday',4),
(1,'2017-03-07','Monday',4),
(1,'2017-03-17','Monday',4),
(1,'2017-03-21','Monday',4);
(1,'2017-03-2','Monday',4);
create table #t_result (id int, a datetime, dy varchar(10),t int);
insert into #t_result values
(1,'2017-01-03','Tuesday',29),
(1,'2017-02-14','Monday',22)
select * from #t
select * from #t_result
Thanks in advance
You can do some window function manipulation and output every 6th row (modulo operator on ROW_NUMBER).
SELECT
id, a, [sum]
FROM
(
SELECT
id
, FIRST_VALUE( a ) OVER (ORDER BY a ROWS 5 PRECEDING) AS a
, SUM( t ) OVER (ORDER BY a ROWS 5 PRECEDING) AS [sum]
, ROW_NUMBER() OVER (ORDER BY a) AS rownum
FROM
#t
) AS data
WHERE
rownum % 6 = 0
--Try Using While Loop
BEGIN TRAN
CREATE TABLE #t (id INT, a DATETIME ,dy VARCHAR(10), t INT);
CREATE TABLE #t_result (id INT, a DATETIME,dy VARCHAR(10),t INT);
CREATE TABLE #Temp (id INT, a DATETIME, t INT, dy VARCHAR(10),temp_count INT);
INSERT INTO #T VALUES
(1,'2017-01-03','Thursday',7),
(1,'2017-01-10','Thursday',5),
(1,'2017-01-17','Thursday',5),
(1,'2017-01-24','Thursday',2),
(1,'2017-01-31','Thursday',6),
(1,'2017-02-07','Thursday',4),
(1,'2017-02-14','Thursday',5),
(1,'2017-02-21','Monday',2),
(1,'2017-02-28','Monday',4),
(1,'2017-03-07','Monday',4),
(1,'2017-03-17','Monday',4),
(1,'2017-03-21','Monday',4),
(1,'2017-03-2' ,'Monday',4)
DECLARE #Strt INT,#End INT
SELECT *, ROW_NUMBER()OVER(ORDER BY ID)rownum INTO #Temp_data FROM #t
SET #Strt=1
SELECT #End= MAX(rownum) FROM #Temp_data
WHILE #Strt<= #End BEGIN
DECLARE #Id INT , #T INT , #Date DATETIME, #total INT, #count INT, #Temp_count INT, #D DATETIME, #Dy VARCHAR(10)
SELECT #Id= Id, #T=t, #Dy=dy, #Date= a FROM #Temp_data WHERE rownum= #Strt
INSERT INTO #Temp
SELECT #Id, #Date, #T, #Dy,1
SELECT #Temp_count= COUNT(*) FROM #Temp
IF #Temp_count=6 BEGIN
SELECT *,ROW_NUMBER()OVER(Order by ID)rownum INTO #tt FROM #Temp
SELECT #D=a FROM #tt WHERE rownum=1
INSERT INTO #t_result
SELECT ID, #D,dy,SUM(t)
FROM #Temp
WHERE DATEPART(yyyy, a) = YEAR(DATEADD(year,-1,GETDATE()))AND dy = DATENAME(DW,GETDATE())
GROUP BY id,dy
HAVING COUNT(*)=6
DELETE FROM #Temp
DROP TABLE #tt
END
SET #Strt= #Strt +1
END
SELECT * FROM #t_result
ROLLBACK TRAN
Try this:
SELECT MIN(D.id)Id,MIN(D.a)a,D.dy,SUM(D.t)T
FROM(
select *,ROW_NUMBER() OVER(PARTITION BY id,dy ORDER BY a)RN
from #t
)D
WHERE D.RN<=6
GROUP BY D.dy
ORDER BY a
OutPut:
Id a dy T
1 2017-01-03 00:00:00.000 Tuesday 29
1 2017-02-21 00:00:00.000 Monday 22

Break row out into multiple rows then collapse values back

OK - I have a table - where I can have a row with multiple quanties - what I need to be able to do is to take all rows where there is a qty > 1 - create multiple rows - one for each qty - perform a simple calculation against each row - say multiply the val field by 2 - and then roll the rows back up into another temp table or something...?
DECLARE #table TABLE (id int IDENTITY(1,1),
code varchar(10),
codeStatus varchar,
qty int,
val money)
INSERT INTO #table
SELECT
'12345',
'T',
2,
1
A numbers table is your friend here.
The join against the numbers table effectively performs your expansion. The code below is essentially just the 'expansion' part of your question. After this its trivial to apply whatever transformations you need, push into temp table and so on.
/*
--create numbers table if don't already have one...
select top 1000000 row_number() over(order by t1.number) as N
into dbo.Numbers
from master..spt_values t1
cross join master..spt_values t2
*/
DECLARE #table TABLE (id int IDENTITY(1,1),code varchar(10), codeStatus varchar, qty int, val money)
INSERT INTO #table SELECT '12345', 'T', 2, 1
select t.id, t.code, t.codeStatus, t.qty, t.val
from #table t
inner join dbo.Numbers n on n.N <= t.qty

Is there a way to return more than 1 row in select without using existing tables

Simple question, just out of curiosity.
For example select 1,2,3 that will show table with one column and three rows.
Something like this: select values(1),(2),(3)
*with one select statement
An example for my comment in your post.
DECLARE #TABLE TABLE (ONE INT, TWO INT, THREE INT)
INSERT INTO #TABLE VALUES (1,2,3)
SELECT UP.COL, UP.VALUE
FROM #TABLE
UNPIVOT (VALUE FOR COL IN (ONE,TWO,THREE)) UP
Query:
DECLARE #t TABLE (i1 INT, i2 INT, i3 INT)
INSERT INTO #t VALUES (1, 2, 3)
SELECT t.*
FROM #t
CROSS APPLY (
VALUES(i1), (i2), (i3)
) t(value)
Output:
value
-----------
1
2
3
Additional info:
http://blog.devart.com/is-unpivot-the-best-way-for-converting-columns-into-rows.html
As it appears there is a simple code that I've been searching for:
select n from (values (1),(2),(3)) D(c);

Need multiple copies of one resultset in sql without using loop

Following is the sample data. I need to make 3 copies of this data in t sql without using loop and return as one resultset. This is sample data not real.
42 South Yorkshire
43 Lancashire
44 Norfolk
Edit: I need multiple copies and I have no idea in advance that how many copies I need I have to decide this on the basis of dates. Date might be 1st jan to 3rd Jan OR 1st jan to 8th Jan.
Thanks.
Don't know about better but this is definatley more creative! you can use a CROSS JOIN.
EDIT: put some code in to generate a date range, you can change the date range, the rows in the #date are your multiplier.
declare #startdate datetime
, #enddate datetime
create table #data1 ([id] int , [name] nvarchar(100))
create table #dates ([date] datetime)
INSERT #data1 SELECT 42, 'South Yorkshire'
INSERT #data1 SELECT 43, 'Lancashire'
INSERT #data1 SELECT 44, 'Norfolk'
set #startdate = '1Jan2010'
set #enddate = '3Jan2010'
WHILE (#startdate <= #enddate)
BEGIN
INSERT #dates SELECT #startdate
set #startdate=#startdate+1
END
SELECT [id] , [name] from #data1 cross join #dates
drop table #data1
drop table #dates
You could always use a CTE to do the dirty work
Replace the WHERE Counter < 4 with the amount of duplicates you need.
CREATE TABLE City (ID INTEGER PRIMARY KEY, Name VARCHAR(32))
INSERT INTO City VALUES (42, 'South Yorkshire')
INSERT INTO City VALUES (43, 'Lancashire')
INSERT INTO City VALUES (44, 'Norfolk')
/*
The CTE duplicates every row from CTE for the amount
specified by Counter
*/
;WITH CityCTE (ID, Name, Counter) AS
(
SELECT c.ID, c.Name, 0 AS Counter
FROM City c
UNION ALL
SELECT c.ID, c.Name, Counter + 1
FROM City c
INNER JOIN CityCTE cte ON cte.ID = c.ID
WHERE Counter < 4
)
SELECT ID, Name
FROM CityCTE
ORDER BY 1, 2
DROP TABLE City
This may not be the most efficient way of doing it, but it should work.
(select ....)
union all
(select ....)
union all
(select ....)
Assume the table is named CountyPopulation:
SELECT * FROM CountyPopulation
UNION ALL
SELECT * FROM CountyPopulation
UNION ALL
SELECT * FROM CountyPopulation
Share and enjoy.
There is no need to use a cursor. The set-based approach would be to use a Calendar table. So first we make our calendar table which need only be done once and be somewhat permanent:
Create Table dbo.Calendar ( Date datetime not null Primary Key Clustered )
GO
; With Numbers As
(
Select ROW_NUMBER() OVER( ORDER BY S1.object_id ) As [Counter]
From sys.columns As s1
Cross Join sys.columns As s2
)
Insert dbo.Calendar([Date])
Select DateAdd(d, [Counter], '19000101')
From Numbers
Where [Counter] <= 100000
GO
I populated it with a 100K dates which goes into 2300. Obviously you can always expand it. Next we generate our test data:
Create Table dbo.Data(Id int not null, [Name] nvarchar(20) not null)
GO
Insert dbo.Data(Id, [Name]) Values(42,'South Yorkshire')
Insert dbo.Data(Id, [Name]) Values(43, 'Lancashire')
Insert dbo.Data(Id, [Name]) Values(44, 'Norfolk')
GO
Now the problem becomes trivial:
Declare #Start datetime
Declare #End datetime
Set #Start = '2010-01-01'
Set #End = '2010-01-03'
Select Dates.[Date], Id, [Name]
From dbo.Data
Cross Join (
Select [Date]
From dbo.Calendar
Where [Date] >= #Start
And [Date] <= #End
) As Dates
By far the best solution is CROSS JOIN. Most natural.
See my answer here: How to retrieve rows multiple times in SQL Server?
If you have a Numbers table lying around, it's even easier. You can DATEDIFF the dates to give you the filter on the Numbers table