Display results of multiple count in a sql query - sql

There are two table:
Table persons:
P_id Name BirthDate
1 N1 2016-08-02
2 N2 2015-05-02
3 N3 2013-06-01
4 N4 2014-01-09
Table visited:(p_id is foreign key to table persons)
Id. Visitor_id. P_id. Visit_date
1 10 1 2017-03-05
2 11 2 2017-01-01
3 10 2 2017-02-03
4 12 3 2016-05-07
5 11 4 2016-04-09
6 10 1 2017-04-09
We are going to get the count of visited persons who their old are under 1, between 1 and 2, between 2 and 3 at date of visit_date by each visitor_id.
The results like :
Visitor_id Under_one Bet_one_two Bet_two_three
10 2 1 0
11 0 1 1
12 0 0 1
Could anyone help me how write a query in sql server for getting the results?
In above results, 0,1,2 means that we subtract of two date(visited_date - birthdate), for example : the result of 2013/03/05 - 2011/06/07 is between 1 and 2

you can try a pivot query like below
select
visitor_id,
Under_one=ISNULL([0],0),
Bet_one_two=ISNULL([1],0),
Bet_two_three=ISNULL([2],0)
from
(
select visitor_id, datediff(m,BirthDate,visit_date)/12 age_in_years,count(1) count from persons p join
visited v on p.p_id=v.p_id
group by visitor_id,datediff(m,BirthDate,visit_date)/12
) src
pivot
(
max(count) for age_in_years in ([0],[1],[2])
)p
see live demo

/*
DROP TABLE Visited
DROP TABLE Persons
DROP TABLE #Data
DROP TABLE #Results
*/
CREATE TABLE Persons
(
[P_id.] INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
[Name] NVARCHAR(2),
BirthDate DATETIME
)
INSERT INTO PERSONS ([Name],BirthDate) VALUES ('N1','2016-08-02')
INSERT INTO PERSONS ([Name],BirthDate) VALUES ('N2','2015-05-02')
INSERT INTO PERSONS ([Name],BirthDate) VALUES ('N3','2013-06-01')
INSERT INTO PERSONS ([Name],BirthDate) VALUES ('N4','2014-01-09')
GO
CREATE TABLE Visited
(
[ID.] INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
[Visitor_id.] INT,
[P_id.] INT REFERENCES Persons,
Visit_date DATETIME
)
GO
INSERT INTO Visited ([Visitor_id.],[P_id.],Visit_date) VALUES (10,1,'2017-03-05')
INSERT INTO Visited ([Visitor_id.],[P_id.],Visit_date) VALUES (11,2,'2017-01-01')
INSERT INTO Visited ([Visitor_id.],[P_id.],Visit_date) VALUES (10,2,'2017-02-03')
INSERT INTO Visited ([Visitor_id.],[P_id.],Visit_date) VALUES (12,3,'2016-05-07')
INSERT INTO Visited ([Visitor_id.],[P_id.],Visit_date) VALUES (11,4,'2016-04-09')
INSERT INTO Visited ([Visitor_id.],[P_id.],Visit_date) VALUES (10,1,'2017-04-09')
GO
SELECT [Visitor_id.],
CASE WHEN DATEPART(YY,v.visit_date-p.birthdate) = 1900 THEN 'Under_one'
WHEN DATEPART(YY,v.visit_date-p.birthdate) = 1901 THEN 'Bet_one_two'
WHEN DATEPART(YY,v.visit_date-p.birthdate) = 1902 THEN 'Bet_two_three'
END AS Age,
COUNT([Visitor_id.]) AS Number
INTO #Data
FROM Persons p INNER JOIN Visited v on p.[P_id.]=v.[P_id.]
GROUP BY [Visitor_id.],DATEPART(YY,v.visit_date-p.birthdate)
GO
CREATE TABLE #Results
(
Visitor_ID INT,
Under_one INT,
Bet_one_two INT,
Bet_two_three INT
)
GO
DECLARE #Visitor_id INT = (SELECT MIN([Visitor_id.]) FROM #Data)
WHILE #Visitor_id <= (SELECT MAX([Visitor_id.]) FROM #Data)
BEGIN
INSERT INTO #Results VALUES
(
(SELECT #Visitor_id)
,
(SELECT Number FROM #Data WHERE [Visitor_id.]=#Visitor_id AND Age = 'Under_one')
,
(SELECT Number FROM #Data WHERE [Visitor_id.]=#Visitor_id AND Age = 'Bet_one_two')
,
(SELECT Number FROM #Data WHERE [Visitor_id.]=#Visitor_id AND Age = 'Bet_two_three')
)
SET #Visitor_id = #Visitor_id + 1
END
UPDATE #Results SET Under_one = 0 WHERE Under_one IS NULL
GO
UPDATE #Results SET Bet_one_two = 0 WHERE Bet_one_two IS NULL
GO
UPDATE #Results SET Bet_two_three = 0 WHERE Bet_two_three IS NULL
GO
SELECT * FROM #Results

How about something like:
CREATE TABLE persons
(p_id int, name varchar(5), birthday date);
INSERT INTO persons
(p_id, name, birthday)
VALUES
(1, 'N1', '2016-08-02'),
(2, 'N2', '2015-05-02'),
(3, 'N3', '2013-06-01'),
(4, 'N4', '2014-01-09');
CREATE TABLE visited
(id int, visitor_id int,p_id int, visit_date date)
;
INSERT INTO visited(id, visitor_id,p_id, visit_date)
VALUES
(1,10,1,'2017-03-05'),
(2,11,2,'2017-01-01'),
(3,10,2,'2017-02-03'),
(4,12,3,'2016-05-07'),
(5,11,4,'2016-04-09'),
(6,10,1,'2017-04-09');
WITH visitAge(visitor_ID, VisitAge) AS
(SELECT
v.visitor_ID, DateDiff(Year, birthday,visit_date) as VisitAge
FROM visited v
INNER JOIN persons p on v.p_ID = p.p_ID
)
SELECT
visitor_ID,
SUM(CASE WHEN VisitAge < 1 THEN 1 ELSE 0 END ) AS under_one,
SUM(CASE WHEN VisitAge >= 1 AND VisitAge < 2 THEN 1 ELSE 0 END ) AS Bet_one_two,
SUM(CASE WHEN VisitAge >= 2 AND VisitAge < 3 THEN 1 ELSE 0 END ) AS Bet_two_three
FROM
visitAge
GROUP BY visitor_ID;
not durable solution...but for what I see in the question...it's a start for you....
SQL Fiddle link

Related

SQL COUNT the number of records on a certain date

I trying to create a SQL query/stored procedure to count the number of applications in-progress on a certain day for a certain team.
Where I am having trouble is the following scenario: when the application is transferred to another user, the count for the day should not double count (a count for each team on the day of transfer) and should go to the transferred user.
My Tables
**Users**
Id || Name || TeamId
---------------------------------
1 User 1 1
2 User 2 2
**Application**
Id || Name
-------------
1 Application1
**ApplicationUser**
Id || ApplicationId || UserId || AssignedDate || UnassignedDate
----------------------------------------------------------
1 1 1 2018-03-01 2018-03-02
2 1 2 2018-03-02 2018-03-03
so in the Stored Procedure I am sending a date in as a parameter and the result i want to return is the following.
Date || Team 1 || Team 2 || Total
-------------------------------------------
2018-03-02 0 1 1
so if I put all results together they would look like this.
Date || Team 1 || Team 2 || Total
-------------------------------------------
2018-02-28 0 0 0
2018-03-01 1 0 1
2018-03-02 0 1 1
2018-03-03 0 1 1
Thank you very much in advance :)
Try this:
DDL:
Here I define table variables and insert data you provided:
declare #users table (id int, name varchar(10), teamid int)
insert into #users values (1, 'user1', 1),(2, 'user2',2)
declare #application table (id int, name varchar(15))
insert into #application values (1, 'application1')
declare #applicationuser table (id int, applicationid int, userid int, assigneddate date, unassigneddate date)
insert into #applicationuser values (1,1,1,'2018-03-01','2018-03-02'),(2,1,2,'2018-03-02','2018-03-03')
Query:
--here I sum values for each team using cumulative sum
select [date],
sum(team1) over (order by [date] rows between unbounded preceding and current row) [team1],
sum(team2) over (order by [date] rows between unbounded preceding and current row) [team2],
sum(total) over (order by [date] rows between unbounded preceding and current row) [total]
from (
--here I am pivoting inner query, replacing NULL values using COALESCE
select [date],
coalesce(max(case when teamid = 1 then value end), 0) [team1],
coalesce(max(case when teamid = 2 then value end), 0) [team2],
coalesce(max(case when teamid = 1 then value end), 0) + coalesce(max(case when teamid = 2 then value end), 0) [total]
from (
--here I join assigned and unassigned dates with team ids
select [AU].assigneddate [date], [U].teamid, 1 [value] from #applicationuser [AU]
join #users [U] on [AU].userid = [U].id
union all
select [AU].unassigneddate, [U].teamid, -1 from #applicationuser [AU]
join #users [U] on [AU].userid = [U].id
) a
group by [date]
) a
In order to understand this better is to try every query separatly, i.e. execute most inner query first, then wrap it with outer query and see the results. This way you'll know what's happening at each step.
These kind of queries are best dealt with using a dates table. If you don't have one in your database already I strongly suggest you get one.
In the meanwhile, you can create a dates table on the fly using either an inline table valued function or a derived table within your query (Note I have added an additional open application):
-- Declare test data
declare #users table (id int, name varchar(10), teamid int);
declare #application table (id int, name varchar(15));
declare #applicationuser table (id int, applicationid int, userid int, assigneddate date, unassigneddate date);
insert into #users values (1, 'user1', 1),(2, 'user2',2);
insert into #application values (1, 'application1'),(2, 'application1');
insert into #applicationuser values (1,1,1,'2018-03-01','2018-03-02'),(2,1,2,'2018-03-02','2018-03-03'),(2,2,2,'2018-03-02','2018-03-05');
-- Find the maximum date range possible to create a dates table that covers all possible application periods
declare #MinDate date = (select min(AssignedDate) from #applicationuser);
declare #MaxDate date = (select max(UnassignedDate) from #applicationuser);
-- This is a derived table that simply returns 10 rows
with t(t) as(select * from(values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1))t(t))
-- This then CROSS JOINs the 10 rows to create 10*10*10*10*10 = 100,000 rows
-- Then uses the ROW_NUMBER function to add a number of days to the #MinDate value, to get a table of incrementing dates
,d(d) as(select top(datediff(day,#MinDate,#MaxDate)+1) dateadd(day,row_number() over (order by (select null))-1,#MinDate) from t,t t2,t t3,t t4,t t5)
select d.d -- Output is a row per date and teamid where there was an open application.
,u.teamid -- When grouped together this gives you a COUNT of open applications by teamid
,count(1) as OpenApplications
from d
join #ApplicationUser as au
on d.d between au.assigneddate and au.unassigneddate
join #users as u
on au.userid = u.id
group by d.d
,u.teamid
order by d.d
,u.teamid
Output:
+------------+--------+------------------+
| d | teamid | OpenApplications |
+------------+--------+------------------+
| 2018-03-01 | 1 | 1 |
| 2018-03-02 | 1 | 1 |
| 2018-03-02 | 2 | 2 |
| 2018-03-03 | 2 | 2 |
| 2018-03-04 | 2 | 1 |
| 2018-03-05 | 2 | 1 |
+------------+--------+------------------+
I have purposefully not pivoted your data to match your desired output as this is almost always a bad idea. As your number of teams change, your number and names of columns outputted will change, which will require constant maintenance. Instead, you should just output a normal set of data and leave the pivoting to the presentation layer once it eventually gets there.
is this use full:
DECLARE #users TABLE (id INT, name VARCHAR(10), teamid INT)
INSERT INTO #users VALUES (1, 'user1', 1),(2, 'user2',2)
DECLARE #application TABLE (id INT, name VARCHAR(15))
INSERT INTO #application VALUES (1, 'application1')
DECLARE #applicationuser TABLE (id INT, applicationid INT, userid INT, assigneddate DATE, unassigneddate DATE)
INSERT INTO #applicationuser VALUES (1,1,1,'2018-03-01','2018-03-02'),(2,1,2,'2018-03-02','2018-03-03')
DECLARE #assignment TABLE([date] DATE,teamid INT,[value] INT)
INSERT INTO #assignment
SELECT [AU].assigneddate [date], [U].teamid, 1 [value]
FROM #applicationuser [AU]
JOIN #users [U] ON [AU].userid = [U].id
INSERT INTO #assignment
SELECT [AU].unassigneddate, [U].teamid,
CASE WHEN LEAD(AssignedDate) OVER(ORDER BY [AU].id)=unassigneddate
THEN -1
ELSE
1
END
FROM #applicationuser [AU]
JOIN #users [U] ON [AU].userid = [U].id
SELECT b.[date],
CASE WHEN t1.teamid=1
THEN 1
ELSE
0
END AS Team1,
CASE WHEN t1.teamid=2
THEN 1
ELSE
0
END AS Team2,
total
FROM
(
SELECT [date], MAX([value]) AS Total
FROM #assignment
group by [date]
)b
INNER JOIN #assignment t1 ON b.Total=t1.Value AND b.[date]=t1.[date]
ORDER BY b.[date]
Thank you very much for all your answers.
I have been trying this myself as well and I seem to have found the answer to my question.
DECLARE #DATE DATETIME
SELECT #DATE = '20180301'
SELECT ApplicationId, Max(UnassignedDate) as UnassignedDate
INTO #TempApplicationUsers
FROM ApplicationUsers
WHERE #DATE > DAteAdd(Day, -1, AssignedDate) and (#DATE < UnassignedDate OR
UnassignedDate is NULL)
Group BY ApplicationId
SELECT * From #TempApplicationUsers
SELECT UserId, COUNT(*) FROM ApplicationUsers, #TempApplicationUsers
WHERE ApplicationUsers.ApplicationId = #TempApplicationUsers.ApplicationId
and ISNULL(ApplicationUsers.UnassignedDate, 0) =
ISNULL(#TempApplicationUsers.UnassignedDate, 0)
GROUP BY UserId
DROP TABLE #TempApplicationUsers
This returns the count for each user on that day and from this I can get the count for each team by the TeamId in the users table.
Thank you again

SQL get consecutive days ignoring weekend

I have a table with following format:
ID ID1 ID2 DATE
1 1 1 2018-03-01
2 1 1 2018-03-02
3 1 1 2018-03-05
4 1 1 2018-03-06
5 1 1 2018-03-07
6 2 2 2018-03-05
7 2 2 2018-03-05
8 2 2 2018-03-06
9 2 2 2018-03-07
10 2 2 2018-03-08
From this table I have to get all records where ID1 and ID2 are the same in that column and where DATE is 5 consecutive work days (5 dates in a row, ignoring missing dates for Saturday/Sunday; ignore holidays).
I have really no idea how to achieve this. I did search around, but couldn't find anything that helped me. So my question is, how can I achieve following output?
ID ID1 ID2 DATE
1 1 1 2018-03-01
2 1 1 2018-03-02
3 1 1 2018-03-05
4 1 1 2018-03-06
5 1 1 2018-03-07
SQLFiddle to mess around
Assuming you have no duplicates and work is only on weekdays, then there is a simplish solution for this particular case. We can identify the date 4 rows ahead. For a complete week, it is either 4 days ahead or 6 days ahead:
select t.*
from (select t.*, lead(dat, 4) over (order by id2, dat) as dat_4
from t
) t
where datediff(day, dat, dat_4) in (4, 6);
This happens to work because you are looking for a complete week.
Here is the SQL Fiddle.
select t.* from
(select id1,id2,count(distinct dat) count from t
group by id1,id2
having count(distinct dat)=5) t1 right join
t
on t.id1=t1.id1 and t.id2=t1.id2
where count=5
Check this-
Dates of Two weeks with 10 valid dates
http://sqlfiddle.com/#!18/76556/1
Dates of Two weeks with 10 non-unique dates
http://sqlfiddle.com/#!18/b4299/1
and
Dates of Two weeks with less than 10 but unique
http://sqlfiddle.com/#!18/f16cb/1
This query is very verbose without LEAD or LAG and it is the best I could do on my lunch break. You can probably improve on it given the time.
DECLARE #T TABLE
(
ID INT,
ID1 INT,
ID2 INT,
TheDate DATETIME
)
INSERT #T SELECT 1,1,1,'03/01/2018'
INSERT #T SELECT 2,1,1,'03/02/2018'
INSERT #T SELECT 3,1,1,'03/05/2018'
INSERT #T SELECT 4,1,1,'03/06/2018'
INSERT #T SELECT 5,1,1,'03/07/2018'
--INSERT #T SELECT 5,1,1,'03/09/2018'
INSERT #T SELECT 6,2,2,'03/02/2018'
INSERT #T SELECT 7,2,2,'03/05/2018'
INSERT #T SELECT 8,2,2,'03/05/2018'
--INSERT #T SELECT 9,2,2,'03/06/2018'
INSERT #T SELECT 10,2,2,'03/07/2018'
INSERT #T SELECT 11,2,2,'03/08/2018'
INSERT #T SELECT 12,2,2,'03/15/2018'
INSERT #T SELECT 13,1,1,'04/01/2018'
INSERT #T SELECT 14,1,1,'04/02/2018'
INSERT #T SELECT 15,1,1,'04/05/2018'
--SELECT * FROM #T
DECLARE #LowDate DATETIME = DATEADD(DAY,-1,(SELECT MIN(TheDate) FROM #T))
DECLARE #HighDate DATETIME = DATEADD(DAY,1,(SELECT MAX(TheDate) FROM #T))
DECLARE #DaysThreshold INT = 5
;
WITH Dates AS
(
SELECT DateValue=#LowDate
UNION ALL
SELECT DateValue + 1 FROM Dates
WHERE DateValue + 1 < #HighDate
),
Joined AS
(
SELECT * FROM Dates LEFT OUTER JOIN #T T ON T.TheDate=Dates.DateValue
),
Calculations AS
(
SELECT
ID=MAX(J1.ID),
J1.ID1,J1.ID2,
J1.TheDate,
LastDate=MAX(J2.TheDate),
LastDateWasWeekend = CASE WHEN ((DATEPART(DW,DATEADD(DAY,-1,J1.TheDate) ) + ##DATEFIRST) % 7) NOT IN (0, 1) THEN 0 ELSE 1 END,
Offset = DATEDIFF(DAY,MAX(J2.TheDate),J1.TheDate)
FROM
Joined J1
LEFT OUTER JOIN Joined J2 ON J2.ID1=J1.ID1 AND J2.ID2=J1.ID2 AND J2.TheDate<J1.TheDate
WHERE
NOT J1.ID IS NULL
GROUP BY J1.ID1,J1.ID2,J1.TheDate
)
,FindValid AS
(
SELECT
ID,ID1,ID2,TheDate,
IsValid=CASE
WHEN LastDate=TheDate THEN 0
WHEN LastDate IS NULL THEN 1
WHEN Offset=1 THEN 1
WHEN Offset>3 THEN 0
WHEN Offset<=3 THEN
LastDateWasWeekend
END
FROM
Calculations
UNION
SELECT DISTINCT ID=NULL,ID1,ID2, TheDate=#HighDate,IsValid=0 FROM #T
),
FindMax As
(
SELECT
This.ID,This.ID1,This.ID2,This.TheDate,MaxRange=MIN(Next.TheDate)
FROM
FindValid This
LEFT OUTER JOIN FindValid Next ON Next.ID2=This.ID2 AND Next.ID1=This.ID1 AND This.TheDate<Next.TheDate AND Next.IsValid=0
GROUP BY
This.ID,This.ID1,This.ID2,This.TheDate
),
FindMin AS
(
SELECT
This.ID,This.ID1,This.ID2,This.TheDate,This.MaxRange,MinRange=MIN(Next.TheDate)
FROM
FindMax This
LEFT OUTER JOIN FindMax Next ON Next.ID2=This.ID2 AND Next.ID1=This.ID1 AND This.TheDate<Next.MaxRange-- AND Next.IsValid=0 OR Next.TheDate IS NULL
GROUP BY
This.ID,This.ID1,This.ID2,This.TheDate,This.MaxRange
)
,Final AS
(
SELECT
ID1,ID2,MinRange,MaxRange,SequentialCount=COUNT(*)
FROM
FindMin
GROUP BY
ID1,ID2,MinRange,MaxRange
)
SELECT
T.ID,
T.ID1,
T.ID2,
T.TheDate
FROM #T T
INNER JOIN Final ON T.TheDate>= Final.MinRange AND T.TheDate < Final.MaxRange AND T.ID1=Final.ID1 AND T.ID2=Final.ID2
WHERE
SequentialCount>=#DaysThreshold
OPTION (MAXRECURSION 0)

Generate Unique Number Company Wise + Year Wise

I have one table containing columns: PurchaseOrderID, CompanyID and CreatedDate. I want a column named PONo in this table that will automatically have values from previous column like : PO/2016(Year from CreatedDate)/001(value will increment for same year and same company id).
My expected table is as below:
PurchaseOrderID CompanyID PONo CreatedDate
1 1 PO/2016/001 2016-01-31
2 1 PO/2016/002 2016-02-22
3 1 PO/2016/003 2016-05-25
4 2 PO/2016/001 2016-09-1
5 2 PO/2016/002 2016-10-11
6 2 PO/2016/003 2016-12-31
7 1 PO/2017/001 2017-01-31
8 1 PO/2017/002 2017-02-2
9 1 PO/2017/003 2017-05-20
10 2 PO/2017/001 2017-06-25
11 2 PO/2017/002 2017-07-15
12 2 PO/2017/003 2017-08-22
From This table I want to generate and update PONo like above table.
I want query to generate PONo.
When I insert new record in table then PONo generates automatically from this record.
Note: If need to add any column let me know.
You may looking for this
WITH CTE AS(
SELECT PurchaseOrderID,
CompanyID,
CreatedDate,
ROW_NUMBER() OVER (PARTITION BY CompanyID,YEAR(CreatedDate) ORDER BY CreatedDate) AS RN
FROM TableName
)
SELECT PurchaseOrderID,
CompanyID,
'PO/'+CAST(YEAR(CreatedDate) AS VARCHAR(5))+'/'+RIGHT('00'+CAST(RN AS VRACHAR(5),3)),
CreatedDate
FROM CTE
Give this a try...
IF OBJECT_ID('tempdb..#TestData', 'U') IS NOT NULL
DROP TABLE #TestData;
CREATE TABLE #TestData (
PurchaseOrderID int NOT NULL PRIMARY KEY,
CompanyID int NOT NULL,
PONo CHAR(11) NULL,
CreatedDate DATE NOT NULL
);
INSERT #TestData(PurchaseOrderID, CompanyID, CreatedDate) VALUES
(1 , 1, '2016-01-31'),
(2 , 1, '2016-02-22'),
(3 , 1, '2016-05-25'),
(4 , 2, '2016-09-01'),
(5 , 2, '2016-10-11'),
(6 , 2, '2016-12-31'),
(7 , 1, '2017-01-31'),
(8 , 1, '2017-02-02'),
(9 , 1, '2017-05-20'),
(10, 2, '2017-06-25'),
(11, 2, '2017-07-15'),
(12, 2, '2017-08-22');
-- SELECT * FROM #TestData td;
--=========================================
SELECT
*,
PONo = CONCAT('PO/', YEAR(td.CreatedDate), '/', RIGHT(CONCAT('000',
ROW_NUMBER() OVER (PARTITION BY td.CompanyID, YEAR(td.CreatedDate) ORDER BY td.PurchaseOrderID)), 3))
FROM
#TestData td;
Results...
PurchaseOrderID CompanyID PONo CreatedDate PONo
--------------- ----------- ----------- ----------- -------------------
1 1 NULL 2016-01-31 PO/2016/001
2 1 NULL 2016-02-22 PO/2016/002
3 1 NULL 2016-05-25 PO/2016/003
7 1 NULL 2017-01-31 PO/2017/001
8 1 NULL 2017-02-02 PO/2017/002
9 1 NULL 2017-05-20 PO/2017/003
4 2 NULL 2016-09-01 PO/2016/001
5 2 NULL 2016-10-11 PO/2016/002
6 2 NULL 2016-12-31 PO/2016/003
10 2 NULL 2017-06-25 PO/2017/001
11 2 NULL 2017-07-15 PO/2017/002
12 2 NULL 2017-08-22 PO/2017/003
If you want to generate new sequence logic.
CREATE TABLE PO_wise_seq
(
CompanyID BIGINT,
year_ INT,
seq BIGINT IDENTITY(1,1)
)
DECLARE #CompanyID BIGINT =332
DECLARE #Year_id BIGINT =2016
INSERT INTO PO_wise_seq VALUES (#CompanyID,#Year_id)
select CompanyID
,cast(#CompanyID as nvarchar) +'/' +cast(#Year_id as nvarchar)+'/'+cast(count(1) as nvarchar) as seq
FROM PO_wise_seq
WHERE CompanyID=#CompanyID
AND year_=#Year_id
GROUP BY CompanyID,year_
If you want to generate new sequence logic.
CREATE TABLE PO_wise_seq
(
PO BIGINT,
year_ INT,
seq BIGINT IDENTITY(1,1)
)
DECLARE #PO_ID BIGINT =332
DECLARE #Year_id BIGINT =2016
INSERT INTO PO_wise_seq VALUES (#PO_ID,#Year_id)
select PO,
cast(#PO_ID as nvarchar) +'/' +cast(#Year_id as nvarchar)+'/'+cast(count(1) as nvarchar) as seq
FROM PO_wise_seq
WHERE PO=#PO_ID
AND year_=#Year_id
GROUP BY PO,year_

How to use aggregate function in update in SQL server 2012

I Tried as shown below:
CREATE TABLE #TEMP
(
ID INT,
EmpID INT,
AMOUNT INT
)
INSERT INTO #TEMP VALUES(1,1,10)
INSERT INTO #TEMP VALUES(2,1,5)
INSERT INTO #TEMP VALUES(3,2,6)
INSERT INTO #TEMP VALUES(4,3,8)
INSERT INTO #TEMP VALUES(5,3,10)
.
.
.
SELECT * FROM #TEMP
ID EmpID AMOUNT
1 1 10
2 1 5
3 2 6
4 3 8
5 4 10
UPDATE #TEMP
SET AMOUNT = SUM(AMOUNT) - 11
Where EmpID = 1
Expected Output:
Table consists of employeeID's along with amount assigned to Employee I need to subtract amount from amount filed depending on employee usage. Amount "10" should be deducted from ID = 1 and amount "1" should be deducted from ID = 2.
Amount: Credits available for that particular employee depending on date.
So i need to reduce credits from table depending on condition first i need to subtract from old credits. In my condition i need to collect 11 rupees from empID = 1 so first i need to collect 10 rupee from ID=1 and 1 rupee from the next credit i.e ID=2. For this reason in my expected output for ID=1 the value is 0 and final output should be like
ID EmpID AMOUNT
1 1 0
2 1 4
3 2 6
4 3 8
5 4 10
Need help to update records. Check error in my update statement.
Declare #Deduct int = -11,
#CurrentDeduct int = 0 /*this represent the deduct per row */
update #TEMP
set #CurrentDeduct = case when abs(#Deduct) >= AMOUNT then Amount else abs(#Deduct) end
, #Deduct = #Deduct + #CurrentDeduct
,AMOUNT = AMOUNT - #CurrentDeduct
where EmpID= 1
I think you want the following: subtract amounts from 11 while remainder is positive. If this is true, here is a solution with recursive cte:
DECLARE #t TABLE ( id INT, amount INT )
INSERT INTO #t VALUES
( 1, 10 ),
( 2, 5 ),
( 3, 3 ),
( 4, 2 );
WITH cte
AS ( SELECT * , 17 - amount AS remainder
FROM #t
WHERE id = 1
UNION ALL
SELECT t.* , c.remainder - t.amount AS remainder
FROM #t t
CROSS JOIN cte c
WHERE t.id = c.id + 1 AND c.remainder > 0
)
UPDATE t
SET amount = CASE WHEN c.remainder > 0 THEN 0
ELSE -remainder
END
FROM #t t
JOIN cte c ON c.id = t.id
SELECT * FROM #t
Output:
id amount
1 0
2 0
3 1
4 2
Here I use 17 as start remainder.
If you use sql server 2012+ then you can do it like:
WITH cte
AS ( SELECT * ,
17 - SUM(amount) OVER ( ORDER BY id ) AS remainder
FROM #t
)
SELECT id ,
CASE WHEN remainder >= 0 THEN 0
WHEN remainder < 0
AND LAG(remainder) OVER ( ORDER BY id ) >= 0
THEN -remainder
ELSE amount
END
FROM cte
First you should get a cumulative sum on amount:
select
id,
amount,
sum(amount) over (order by id) running_sum
from #TEMP;
From here we should put 0 on rows before running_sum exceeds the value 11. Update the row where the running sum exceeds 11 and do nothing to rows after precedent row.
select
id,
amount
running_sum,
min(case when running_sum > 11 then id end) over () as decide
from (
select
id,
amount,
sum(amount) over (order by id) running_sum
from #TEMP
);
From here we can do the update:
merge into #TEMP t
using (
select
id,
amount
running_sum,
min(case when running_sum > 11 then id end) over () as decide
from (
select
id,
amount,
sum(amount) over (order by id) running_sum
from #TEMP
)
)a on a.id=t.id
when matched then update set
t.amount = case when a.id = a.decide then a.running_sum - 11
when a.id < a.decide then 0
else a.amount
end;
See an SQLDFIDDLE

T-SQL How to select min, max and first row from table from duplicate values

DateTime -- Unit -- Client --- Qty
03/02/2013 08:00:01 -- 3 -- 1 --- 1
03/02/2013 08:00:02 -- 3 -- 2 --- 1
03/02/2013 08:00:03 -- 3 -- 3 --- 2
03/02/2013 08:00:04 -- 3 -- 3 --- 2
03/02/2013 08:00:05 -- 3 -- 3 --- 5
03/02/2013 08:00:06 -- 3 -- 3 --- 4
03/02/2013 08:00:07 -- 3 -- 4 --- 6
03/02/2013 08:00:08 -- 3 -- 4 --- 67
03/02/2013 08:00:09 -- 3 -- 4 --- 76
03/02/2013 08:00:10 -- 3 -- 4 --- 76
And I want :
DateTime -- Unit -- Client --- Qty
03/02/2013 08:00:01 -- 3 -- 1 --- 1
03/02/2013 08:00:02 -- 3 -- 2 --- 1
03/02/2013 08:00:03 -- 3 -- 3 --- 2
03/02/2013 08:00:05 -- 3 -- 3 --- 5
03/02/2013 08:00:07 -- 3 -- 4 --- 6
03/02/2013 08:00:09 -- 3 -- 4 --- 76
The criteria to filter is get the min and max "Qty" from table and get only the first value when exists duplicate "Qty" values in the same "Unit" and "client" column.
I do the follow T-SQL, but the retrieval is the last "Qty" value when the "Unit" and "client" column are the same, I need the first.
--1
CREATE TABLE Transact
(DateTime DateTime,
Unit INT NULL,
Client INT NULL,
Qty INT NULL
)
INSERT INTO Transact (Datetime,Unit,Client,Qty)
Values ( '03/02/2013 08:00:01',3,1,1)
Values ( '03/02/2013 08:00:02',3,2,1)
Values ( '03/02/2013 08:00:03',3,3,2)
Values ( '03/02/2013 08:00:04',3,3,2)
Values ( '03/02/2013 08:00:05',3,3,5)
Values ( '03/02/2013 08:00:06',3,3,4)
Values ( '03/02/2013 08:00:07',3,4,6)
Values ( '03/02/2013 08:00:08',3,4,67)
Values ( '03/02/2013 08:00:09',3,4,76)
Values ( '03/02/2013 08:00:10',3,4,76)
DECLARE #Total TABLE
(DateTime DateTime,
Unit INT NULL,
Client INT NULL,
Qty INT NULL
)
DECLARE #Uniques TABLE
(DateTime DateTime,
Unit INT NULL,
Client INT NULL,
Qty INT NULL
)
DECLARE #Mini TABLE
(DateTime DateTime,
Unit INT NULL,
Client INT NULL,
Qty INT NULL
)
DECLARE #Maxi TABLE
(DateTime DateTime,
Unit INT NULL,
Client INT NULL,
Qty INT NULL
)
--2
INSERT INTO #Total SELECT * FROM Transact
INSERT INTO #Mini SELECT MIN(Datetime) Datetime,Unit,Client,MIN(Qty) FROM #Total GROUP BY Unit,Client
INSERT INTO #Maxi SELECT MAX(Datetime) Datetime,Unit,Client,MAX(Qty) FROM #Total GROUP BY Unit,Client
--3
INSERT INTO #Uniques SELECT * FROM #Mini UNION SELECT * FROM #Maxi
SELECT * FROM #Uniques
Thanks in advance.
Pablo Geronimo.
Try this:
WITH MinCTE
AS
(
SELECT *,
ROW_NUMBER() OVER(Unit, PARTITION BY Client
ORDER BY Qty, DateTime ) AS RN
FROM Transact
), MaxCTE
AS
(
SELECT *,
ROW_NUMBER() OVER(PARTITION BY Unit, Client
ORDER BY Qty DESC, DateTime) AS RN
FROM Transact
)
SELECT DateTime, Unit, Client, Qty FROM MinCTE WhERE RN = 1
UNION
SELECT DateTime, Unit, Client, Qty FROM MaxCTE WhERE RN = 1;
SQL Fiddle demo
Here's what you can try:
SELECT DISTINCT MIN(DateTime), MIN(Qty), Unit, Client FROM Transact
GROUP BY Unit, Client
UNION
SELECT DISTINCT MAX(DateTime), MAX(Qty), Unit, Client FROM Transact
GROUP BY Unit, Client
First select the records with min and max Qty to a single table, and then select the min DateTime for those records.
SELECT MIN(DateTime), [Transact].Unit, [Transact].Client, [Transact].Qty
FROM (
SELECT DISTINCT Unit, Client, MIN(Qty) as Qty
FROM [Transact]
GROUP BY Unit, Client
UNION
SELECT Unit, Client, MAX(Qty)
FROM [Transact]
GROUP BY Unit, Client
) as MinMax
JOIN [Transact] ON [Transact].Unit = MinMax.Unit AND [Transact].Client = MinMax.Client AND [Transact].Qty = MinMax.Qty
GROUP BY [Transact].Unit, [Transact].Client, [Transact].Qty
I used a subquery but isn’t hard to change it to a memory table if you prefer.