Weekends between weekdays SQL - sql

I have a list of weekday's dates and want to insert rows for weekends/public holidays dates and populate data from previous row in SQL. Pls help.

Your holidays depend on what country you are in. This is the logic used for inserting two days after finding a Friday, similar logic can be applied if you know how to identify holidays, and how long they last.
create table #temp (fechas date, value int)
insert into #temp values ('20160601',2)
insert into #temp values ('20160602',4)
insert into #temp values ('20160603',8)
insert into #temp values ('20160606',2)
insert into #temp values ('20160607',1)
--TABLE
select *, DATEPART(DW,fechas) as dayOfTheWk
into #temp2
from #temp
-- selecting Fridays
declare #Fridays TABLE (fechas date,value int, dayOfTheWk int, nRow int)
insert into #Fridays
select *, DATEPART(DW,fechas) as dayOfTheWk, ROW_NUMBER() over(order by fechas) from #temp
where DATEPART(DW,fechas) = 6
declare #i int = 1, #maxI int
select #maxI = count(1) from #Fridays
while(#i <= #maxI)
begin
declare #x int = 1
while (#x <= 2)
begin
insert into #temp2
select
DATEADD(day,#x,fechas) as fechas, value, DATEPART(DW,DATEADD(day,#x,fechas))
from #Fridays
where nRow = #i
select #x += 1
end
select #i += 1
end
select * from #temp2
fechas value dayOfTheWk
2016-06-01 2 4
2016-06-02 4 5
2016-06-03 8 6
2016-06-04 8 7
2016-06-05 8 1
2016-06-06 2 2
2016-06-07 1 3

Related

Best combination to satisfy a quantity

I have a list of items with the same article but different quantities, and I want to find different subgroups of items that could satisfy a specific quantity.
UNIT
ITEM
Quantity
1
1
40
2
1
50
3
1
60
4
1
60
5
1
60
The quantity to satisfy is between 110 and 120
I want to find all the combinations of units that can reach the sum between 110 and 120.
My solution, for now, is to use sql programming, but don't know if can be done with a query.
declare #units table ( id int,Item int,Quantity int)
insert into #units
values
(1 ,1 ,40),
(2 ,1 ,50),
(3 ,1 ,60),
(4 ,1 ,60),
(5 ,1 ,60)
DECLARE #TEMP TABLE ( ID INT, QUANTITY INT , RANKc INT)
DECLARE #TEMP2 TABLE ( Rmin INT, Rmax INT , sumQ INT)
INSERT INTO #TEMP
SELECT
Id,
Quantity,
row_number() over (order by Quantity asc) as rank_c
FROM #units
where Item=1
select * from #TEMP
DECLARE #RMIN INT =1
DECLARE #RMax INT =2
DECLARE #MaxQ int=120
DECLARE #MinQ int=110
--DECLARE #Count int=1
DECLARE #SumQuantity int
WHILE (#RMax<=(SELECT MAX(RANKc) FROM #TEMP))
BEGIN
select #SumQuantity=sum(QUANTITY) from #TEMP where RANKc between #RMIN and #RMax
if (#SumQuantity between #MinQ and #MaxQ)
begin
insert into #TEMP2 values
(#RMIN,#RMax,#SumQuantity)
set #RMIN=#RMIN+1
set #RMax=#RMIN+1
--break;
end
IF (#SumQuantity < #MinQ)
begin
set #RMax=#RMax+1
end
if (#SumQuantity>#MaxQ)
begin
set #RMIN=#RMIN+1
set #RMax=#RMIN+1
end
END
select * from #TEMP2
Rmin
Rmax
sumQ
2
3
110
3
4
120
4
5
120

How to insert records of the range in table when I define the range in first table in SQL Server 2012

Here I have two table, with the name Table A and Table B.
Table A:
ID From To
-------------------
1 985 992
2 1201 1207
3 1584 1589
Table B:
ID Numbers
---------------------------
1 985
2 986
3 987
4 988
5 989
6 990
7 991
8 992
9 1201
10 1202
11 1203
12 1204
13 1205
14 1206
and the number goes like this. And the table structure as well.
How can such kind of data can be insert. As I define range from 125- 135 in table A, all the number with in this range must be inserted at table B.
Thanks to all the well wisher for their valuable suggestion. Answer has been solve with using trigger.
CREATE TRIGGER trgAfterInsert on samplea
FOR INSERT
AS declare #id int, #from bigint, #to bigint, #number bigint;
select #id=i.id from inserted i;
select #from=i.fromnum from inserted i;
select #to=i.tonum from inserted i;
set #number=#from
while #number<=#to
begin
insert into sampleB (id, numbers) values (#id,#number);
set #number=#number+1
end
Finally the problem is solved. With this inserting data range in table A, data will be automatically inserted in table B with this trigger.
You can do it with a cursor and while loops,
DELCARE #Uid int, #Ustart int, #Uend int, #Ucounter;
DECLARE Ucursor CURSOR
FOR SELECT * FROM TableA ;
OPEN vend_cursor
FETCH NEXT FROM Ucursor
INTO #Uid,#Ustart,#Uend
WHILE ##FETCH_STATUS = 0
BEGIN
SET #Ucounter = #Ustart
WHILE #Ucounter <> #Uend
BEGIN
INSERT INTO TableB
VALUES (#Ucount) -- Set the identity on for id
SET #Ucounter += 1
END
FETCH NEXT FROM Ucursor
INTO #Uid,#Ustart,#Uend
END
CLOSE Ucursor;
Not sure if this is efficient but it works.
DECLARE #range INT = (SELECT [To] - [From] FROM #tableA WHERE [Id] = 1)
DECLARE #count INT = 0
WHILE (#count <= #range)
BEGIN
INSERT INTO #tableB
SELECT [From] + #count FROM #tableA
SET #count = #count + 1
END
I would suggest a recursive CTE:
with cte as (
select from as n, from, to
from a
union all
select n + 1, from, to
from cte
where n < to
)
select n
from cte;
To create a table, you can do:
with cte as (
select from as n, from, to
from a
union all
select n + 1, from, to
from cte
where n < to
)
select identity(), n
into b
from cte;
Notes:
I left the column names as you have them without escaping them. Obviously, from and to are keywords in SQL.
If you have a gap of more than 100, you'll want to use the MAXRECURSION option.
You can insert values just as easily as creating a new table.
Try this,
declare #t table(ID int,Froms int,Tos int)
insert into #t values
(1 , 985 , 992 )
,(2 , 1201 , 1207 )
,(3 , 1584 , 1589 )
declare #table2 table(id int identity(1,1),numbers int)
insert into #table2
select number from #t t
cross apply(
select distinct number from master..spt_values
where number>t.[froms] and number<=t.tos)ca
select * from #table2

SQL subset sum negative values

I have a table valued function that return the set of rows that matches a given sum, It works fine with positive values but not with negatives one.
Can someone modify this function to work with both positive and negative values (price field)
The function take a table with decimal values, then return the first combination of rows that match a given sum in the parameter :
For example if the #psum = 9 and the given table below :
n id price
1 1 4.00
2 2 4.00
3 3 5.00
4 4 6.00
5 5 8.00
The out put is :
select * from SubsetSum2(9)
n id price
3 3 5.00
2 2 4.00
alter FUNCTION [dbo].[SubsetSum2](#psum int )
RETURNS #tt table (n int,id int, price numeric(20,2))
AS
BEGIN
declare #t table (n int IDENTITY(1,1), id int, price numeric(20,2))
insert into #t -- note asc order of book prices
select 1, 4 union all
select 2, 4 union all
select 3, 5 union all
select 4, 6 union all
select 5, 8
declare #rows int, #p numeric(20,2), #sum numeric(20,2) set #sum= 9
delete from #t where price>#sum
set #p=(select sum(price) from #t)
if #p>= #sum
begin --1
set #rows=(select max(n) from #t)
declare #n int, #s numeric(20,2)
set #n=#rows+1 set #s=0
while 0=0
begin --2
while #n>1
begin --3
set #n=#n-1
if #s+(select price from #t where n=#n)<=#sum
and #s+(select sum(price) from #t where n<=#n)>=#sum
begin --4
set #s=#s+(select price from #t where n=#n)
insert into #tt select n, id, price from #t where n=#n
if #s=#sum return ;
end --4
end --3
set #n=(select min(n) from #tt)
set #s=#s-(select price from #tt where n=#n)
delete from #tt where n=#n
if #s=0 and (select sum(price) from #t where n<#n)<#sum break
end --2
end --1
return
END
Use Absolute function ABS(Price) for treating the negatives as positives

How to create loop based on value of row?

I have problem when I use my query bellow to have a looping inside the cursor.
data in table1 will be like this:
id | data
----|---------
A | 4
B | 2
C | 5
the result in table2 should be like this:
id | data
----|---------
A | 1
A | 1
A | 1
A | 1
B | 1
B | 1
C | 1
C | 1
C | 1
C | 1
C | 1
I have SQL query with cursor like this:
DECLARE #table2 table ( id VARCHAR(500), data INTEGER)
DECLARE Cur CURSOR FOR
SELECT id, data FROM table1
OPEN Cur
WHILE ( ##FETCH_STATUS = 0 )
BEGIN
DECLARE #LoopNum INTEGER
DECLARE #tempID VARCHAR(255)
DECLARE #tempDATA INTEGER
FETCH NEXT FROM Cur INTO #tempID, #tempDATA
set #LoopNum = 0
WHILE #LoopNum < #tempDATA
BEGIN
INSERT INTO table2 (id, data)
VALUES( #tempID, 1)
SET #LoopNum = #LoopNum + 1
END
END
CLOSE Cur
DEALLOCATE Cur
SELECT * FROM table2
but the query didn't work. is there something wrong with my query?
Thank you.
Use this query to the expected result.
CREATE TABLE #test
(id CHAR(1),data INT)
INSERT #test VALUES ('A',4)
INSERT #test VALUES('B',2)
INSERT #test VALUES('C',5);
SELECT s.id, 1 AS data
FROM #test s
INNER JOIN
master.dbo.spt_values t ON t.type='P'
AND t.number BETWEEN 1 AND s.data
Note: Refer this Why (and how) to split column using master..spt_values?
You actually don't need a loop
IF OBJECT_ID('TEMPDB..#TEMP') IS NOT NULL
DROP TABLE #TEMP
SELECT 'A' AS ID, 4 AS DATA
INTO #TEMP UNION
SELECT 'B', 2 UNION
SELECT 'C', 5
;WITH CTE AS
(
SELECT 1 AS NUMBER
UNION ALL
SELECT NUMBER + 1
FROM CTE
WHERE NUMBER < 100
)
SELECT T.ID, 1
FROM CTE C
INNER JOIN #TEMP T
ON C.NUMBER <= T.DATA
ORDER BY T.ID
Carefull that if you want ot generate a large set of numbers in the CTE it may become slower.
Use a Recursive CTE which will help you to loop through the records.
CREATE TABLE #test
(id CHAR(1),data INT)
INSERT #test
VALUES ('A',4),('B',2),('C',5);
WITH cte
AS (SELECT 1 AS da,id,data
FROM #test a
UNION ALL
SELECT da + 1,id,data
FROM cte a
WHERE da < (SELECT data
FROM #test b
WHERE a.id = b.id))
SELECT id,
1 AS data
FROM cte
ORDER BY id
i used two loops
1. for each row
2. for number for duplicate insert
SET NOCOUNT on;
DECLARE #t table(row int IDENTITY(1,1),id varchar(10),data int)
INSERT INTO #t
SELECT * from xyz
DECLARE #x table(id varchar(10),data int) --table to hold the new data
DECLARE #i int=(SELECT count (*) from xyz) --number of rows main table
DECLARE #y int --number of duplicate
DECLARE #p int=1 --number of rows
WHILE #i!=0 --loop until last row of main table
BEGIN
SET #y=(SELECT data FROM #t WHERE row=#p) --set #y for number of 'row duplicate'
WHILE #y!=0
BEGIN
INSERT INTO #x
SELECT id,1
FROM #t
WHERE row=#p
SET #y=#y-1
END
SET #p=#p+1
SET #i=#i-1
END
SELECT * FROM #x

get specific rows of table given a rule SQL Server 2008

I have a table like:
ID NAME VAL
----------------------
1 a1*a1 90052
2 a1*a2 236
3 a1*a3 56
4 a1*a4 6072
5 a1*a5 1004
6 a2*a2 4576
7 a2*a3 724
8 a2*a4 230
9 a2*a5 679
10 a3*a3 5
11 a3*a4 644
12 a3*a5 23423
13 a4*a4 42354
14 a4*a5 10199
15 a5*a5 10279
Given a number given S = 5, I want to query
the rows wth id: 1,6,10,13,15
they are a1*a1,a2*a2,a3*a3,a4*a4 and a5*a5
I would like something like:
INSERT #NEW_TABLE (ID,NAME,Value) (
SELECT ordinal, NAME, VAL FROM myTable where id = 1,6,10,13,15)
to get
ID NAME VAL
----------------------
1 a1*a1 90052
2 a2*a2 4576
3 a3*a3 5
4 a4*a4 42354
5 a5*a5 10279
Is there a way to do this for any given S, Maybe wth dynamic sql?
I was getting the formula and I got this:
S=5
ID formula
1 1
6 1+S
10 1+S+ (S-1)
13 1+S+ (S-1) + (S-2)
15 1+S+ (S-1) + (S-2) + (S-3)
Is there a way to do this inside a case or a while loop?
This worked in testing.
You can just inner join on #Tab to limit your results. You probably also want to add some traps for values below 3, which I haven't done.
The basic process is
Declare your #s value
Insert the first two rows since they will always be the same
In a loop, insert one row at a time with an incrementing difference
Loop exits once it has run #s-2 times
Try:
DECLARE #Tab Table (id INT)
DECLARE #S int = 5,
#ct int
DECLARE #cur int = (1 + #S)
INSERT INTO #Tab SELECT 1
INSERT INTO #Tab SELECT (1 + #S)
SET #ct = 1
WHILE #ct <= #S - 2
BEGIN
SET #cur = #cur + (#S - #ct)
INSERT INTO #Tab SELECT #cur
SET #ct = #ct + 1
END
SELECT * FROM #Tab
ORDER BY id
To use this in your query, you can do either:
SELECT ordinal, NAME, VAL
FROM myTable
WHERE id IN (SELECT id FROM #Tab)
-- OR
SELECT ordinal, NAME, VAL
FROM myTable t
INNER JOIN #tab t2
ON t2.id = t.id