assign values to GroupID column for rows - tsql

The following code generates the rows in the screenshot below. The goal is to add a new column called GroupID that assigns the values shown in blue on the right side of the screen shot.
select
*
into #data
from
(
values
(157, 84152, 'termination', '7/31/2017'),
(157, 3025126, 'effective', '8/1/2017'),
(157, 3025126, 'termination', '8/31/2018'),
(157, 157, 'effective', '9/1/2018'),
(1176, 30, 'termination', '5/6/2017'),
(1176, 1176, 'effective', '5/7/2017'),
(1176, 1176, 'termination', '11/3/2017'),
(1176, 30, 'effective', '11/4/2017'),
(1176, 30, 'termination', '5/6/2018'),
(1176, 1176, 'effective', '5/7/2018'),
(1176, 1176, 'termination', '11/9/2018'),
(1176, 30, 'effective', '11/10/2018'),
(1176, 30, 'termination', '5/3/2019'),
(1176, 1176, 'effective', '5/4/2019')
) d (CurrentProducerID, FormerProducerID, DateType, DateValue);
alter table #data alter column DateValue date;
select * from #data;
I have tried using row_number() but it does not give the desired result. Here is my attempt and the outcome:
select
*,
--GroupID = row_number() over(partition by CurrentProducerID order by DateValue)
GroupID = row_number() over(partition by CurrentProducerID, FormerProducerID order by DateValue)
from #data;

One solution can be the below:-
;with ccc as (
select *,ROW_NUMBER() over (order by (select 1)) id from #data
),cte as (
select t1.*,t2.id [t2id] from ccc t1
left outer join ccc t2 on t2.CurrentProducerID=t1.CurrentProducerID
and t2.FormerProducerID=t1.FormerProducerID
and (t2.DateType='termination' and t1.DateType='effective')
and (t1.id+1)=t2.id
),cte2 as (
select cte.id,ROW_NUMBER() over (Partition by CurrentProducerID order by id) [g] from cte where t2id is null
)
select cte.CurrentProducerID , cte.FormerProducerID , cte.DateType , cte.DateValue,isnull(cte2.g,cte3.g) g from cte
left join cte2 on cte.id=cte2.id
left join cte2 cte3 on cte.id+1=cte3.id
Result will be as below:-
CurrentProducerID FormerProducerID DateType DateValue g
157 84152 termination 2017-07-31 1
157 3025126 effective 2017-08-01 2
157 3025126 termination 2018-08-31 2
157 157 effective 2018-09-01 3
1176 30 termination 2017-05-06 1
1176 1176 effective 2017-05-07 2
1176 1176 termination 2017-11-03 2
1176 30 effective 2017-11-04 3
1176 30 termination 2018-05-06 3
1176 1176 effective 2018-05-07 4
1176 1176 termination 2018-11-09 4
1176 30 effective 2018-11-10 5
1176 30 termination 2019-05-03 5
1176 1176 effective 2019-05-04 6

Related

Unpivot in postgres with a column created in the same query

I am trying to unpivot a table with PostgreSQL as described here.
My problem is that I am creating a new column in my query which I want to use in my cross join lateral statement (which results in an SQL error because the original table does not have this column).
ORIGINAL QUESTION:
select
"Name",
case
when "Year"='2020' then "Date"
end as "Baseline"
from "test_table"
EDIT: I am using the example from the referred StackOverflow question:
create table customer_turnover
(
customer_id integer,
q1 integer,
q2 integer,
q3 integer,
q4 integer
);
INSERT INTO customer_turnover VALUES
(1, 100, 210, 203, 304);
INSERT INTO customer_turnover VALUES
(2, 150, 118, 422, 257);
INSERT INTO customer_turnover VALUES
(3, 220, 311, 271, 269);
INSERT INTO customer_turnover VALUES
(3, 320, 211, 171, 269);
select * from customer_turnover;
creates the following output
customer_id q1 q2 q3 q4
1 100 210 203 304
2 150 118 422 257
3 220 311 271 269
3 320 211 171 269
(I used the customer_id 3 twice because this column is not unique)
Essentially, what I would like to do is the following: I would like to calculate a new column qsum:
select customer_id, q1, q2, q3, q4,
q1+q2+q3+q4 as qsum
from customer_turnover
and use this additional column in my unpivoting statement to produce the following output:
customer_id turnover quarter
1 100 Q1
1 210 Q2
1 203 Q3
1 304 Q4
1 817 qsum
2 150 Q1
2 118 Q2
2 422 Q3
2 257 Q4
2 947 qsum
3 220 Q1
3 311 Q2
3 271 Q3
3 269 Q4
3 1071 qsum
3 320 Q1
3 211 Q2
3 171 Q3
3 269 Q4
3 971 qsum
As I do not want to have qsum in my final output, I understand that I cannot use it in my select statement, but even if I would use it like this
select customer_id, t.*, q1, q2, q3, q4,
q1+q2+q3+q4 as qsum
from customer_turnover c
cross join lateral (
values
(c.q1, 'Q1'),
(c.q2, 'Q2'),
(c.q3, 'Q3'),
(c.q4, 'Q4'),
(c.qsum, 'Qsum')
) as t(turnover, quarter)
I receive the following SQL error: ERROR: column c.qsum does not exist
How can I produce my desired output?
Not sure to well understand your issue, maybe a subquery can help :
select s.baseline
from
( select
"Name",
case
when "Year"='2020' then "Date"
end as "Baseline"
from "test_table"
) AS s

Problem Counting Items For an Individual Row

I need to find the count for ActivityID and AdditionalActivityID for each DailyFieldRecordID based on when GroupID = 260 and ItemID is either 1302,1303,1305,1306. The problem I'm having is that regardless of how many rows for each individual DailyFieldRecordID there are, there can only be one ActivityID and one AdditionalActivityID regardless of how many rows comply with the constraints.
Say someone is filling out a form and they list what their Activity for the day was and also what other activity they might have. They can only list one primary activity(ActivityID) and one secondary activity(AdditionalActivity). But during those activities they could participate with multiple groups(GroupID) or people(ItemID). So when I'm running this query I'm able to separate the rows based on the constraints, but I only want to count how many activities they participated in, which will either be 1 or 2 for each DailyFieldRecordID, regardless of how many groups or people were involved. Right now my query is counting each ActivityID and AdditionalActivityID for each row that meets the criteria, which can give me many more than just 1 or 2 for each DailyFieldRecordID. I'm just not sure how I would go about doing this. Any feedback is greatly appreciated.
DailyFieldRecordID: GroupID: ItemID: ActivityID: AdittionalActivityID:
3369320 260 1302 37 0
3369320 260 1305 37 0
3369320 210 2222 37 0
3369320 250 2222 37 0
3372806 260 1302 56 56
3372806 260 1305 56 56
3372806 250 2222 56 56
3388888 260 2222 45 32
Expected Result:
DailyFieldRecordID: Count:
3369320 1
3372806 2
Current Result:
DailyFieldRecordID: Count:
3369320 2
3372806 4
'
select a.DailyFieldRecordID,
count(case when a.ActivityID <>0 then 1 else null end) +
count(case when a.AdditionalActivityID <>0 then 1 else null end) as count
from AB953 a
where a.GroupID= 260 and exists(
select b.DailyFieldRecordID
from AB953 b
where a.DailyFieldRecordID = b.DailyFieldRecordID and b.ItemID in (1302,1303,1305,1306))
group by DailyFieldRecordID
I get this result when trying your data:
DailyfieldrecordID Count
3369320 3
3372806 2
3388888 1
SELECT DailyFieldRecordID,
COUNT(CASE WHEN ActivityID <>0 then 1 else 0 end +
CASE WHEN AdditionalActivityID <>0 then 1 else 0 end) as Count
from Foo
where GroupID= 260 and exists(
select b.DailyFieldRecordID
from fOO b
where DailyFieldRecordID = b.DailyFieldRecordID and b.ItemID in (1302,1303,1305,1306))
group by DailyFieldRecordID
New query: you might need to fiddle with this, not sure if your data is wrong or not....... cant get it to select 3 and then 2:
SELECT DailyFieldRecordID,
COUNT(CASE WHEN ActivityID <>0 then 1 else 0 end +
CASE WHEN AdditionalActivityID <>0 then 1 else 0 end) as Count
from Foo
where GroupID= 260 and DailyFieldRecordID IN(
select b.DailyFieldRecordID
from fOO b
where b.ItemID IN(1302,1303,1305,1306))
group by DailyFieldRecordID
This should do it:
;WITH CTE AS
(
SELECT A.DailyFieldRecordID
,ActivityID = IIF(A.ActivityID = 0, NULL, A.ActivityID)
,AdittionalActivityID = IIF(A.AdittionalActivityID = 0, NULL, A.AdittionalActivityID)
FROM AB953 A
WHERE A.GroupID = 260
AND A.ItemID IN (1302,1303,1305,1306)
)
SELECT DailyFieldRecordID
,CNT = COUNT(DISTINCT ActivityID) + COUNT(DISTINCT AdittionalActivityID)
FROM CTE
GROUP BY DailyFieldRecordID;
I created this DDL and test data for testing:
DROP TABLE IF EXISTS AB953
GO
CREATE TABLE AB953 (
DailyFieldRecordID INT, GroupID INT, ItemID INT, ActivityID INT, AdittionalActivityID INT)
INSERT INTO AB953
VALUES
( 3369320, 260, 1302, 37, 0 )
,( 3369320, 260, 1305, 37, 0 )
,( 3369320, 210, 2222, 37, 0 )
,( 3369320, 250, 2222, 37, 0 )
,( 3372806, 260, 1302, 56, 56 )
,( 3372806, 260, 1305, 56, 56 )
,( 3372806, 250, 2222, 56, 56 )
,( 3388888, 260, 2222, 45, 32 )
GO

Group By - Using Absolute Values

I'm trying to display an accounting report where I show total transactions, voids, the transaction fee, and a total amount for each transaction type.
TransactionType Amount TransactionCount TotalAmount
AgentCredit -$1.00 49 -$49.00
MailFee -$1.25 11 -$13.75
MailFee $1.25 531 $663.75
HardCardFee -$5.00 7 -$35.00
HardCardFee $5.00 239 $1,195.00
QuotaHuntFee -$2.00 1 -$2.00
QuotaHuntFee $2.00 202 $404.00
But what I want to display would look like the following:
TransactionType Amount TransactionCount TotalAmount TotalTrans Voids
AgentCredit -$1.00 49 -$49.00 49 0
MailFee $1.25 520 $650.00 531 11
HardCardFee $5.00 232 $1,160.00 239 7
QuotaHuntFee $2.00 201 $402.00 202 1
Would it be possible to group the transaction types using the absolute value of the Amount and calculate the grand total along with the transaction count & void counts?
This is on SQL Server 2014.
Thanks,
I think this does it
declare #T table (nm varchar(20), prc smallmoney, amt int);
insert into #T values
('AgentCredit', -1.00, 49)
, ('MailFee', -1.25, 11)
, ('MailFee', 1.25, 531)
, ('HardCardFee', -5.00, 7)
, ('HardCardFee', 5.00, 239)
, ('QuotaHuntFee', -2.00, 1)
, ('QuotaHuntFee', 2.00, 202);
with cte as
(
select t.*, (t.prc * t.amt) as net
, count(*) over (partition by t.nm, abs(t.prc)) as cnt
, row_number() over (partition by t.nm, abs(t.prc) order by t.prc) as rn
, lag(t.prc) over (partition by t.nm, abs(t.prc) order by t.prc) as prPrc
, lag(t.amt) over (partition by t.nm, abs(t.prc) order by t.prc) as prAmt
, case when lag(t.prc) over (partition by t.nm, abs(t.prc) order by t.prc) < 0 then t.amt - lag(t.amt) over (partition by t.nm, abs(t.prc) order by t.prc)
else t.amt
end as bal
from #T t
)
select *, ISNULL(t.prAmt, 0) as void
, bal*prc as nnet
from cte t
where t.cnt = 1
or t.rn = 2
order by t.nm, t.prc;
There's a bit of confusion around your results with the data you've provided. HardCardFee has 7 and 23 in the sample you provided, but you want to return 232 for the total?.. MailFee also has some inconsistent math. Also, your 'Voids' returns 0 for the first row; however, it seems as if there are 49?
Perhaps this query could get you started down the right path:
DECLARE #Table TABLE (TransactionType varchar(20), Amount decimal(10,2), TransactionCount int, TotalAmount decimal(10,2))
INSERT #Table
VALUES ('AgentCredit' ,-$1.00 ,49 ,-$49.00 ),
('MailFee' ,-$1.25 ,11 ,-$13.75 ),
('MailFee' ,$1.25 ,531 ,$663.75 ),
('HardCardFee' ,-$5.00 ,7 ,-$35.00 ),
('HardCardFee' ,$5.00 ,23 ,$1195.00 ),
('QuotaHuntFee' ,-$2.00 ,1 ,-$2.00 ),
('QuotaHuntFee' ,$2.00 ,202 ,$404.00 )
;WITH c AS (
SELECT TransactionType, Amount, TransactionCount, TotalAmount,
CASE WHEN t.Amount + ABS(t.Amount) = 0 THEN '-' ELSE '' END +
CAST(t.TransactionCount AS VARCHAR(10)) AS TCount
FROM #Table t
)
SELECT t.TransactionType
,MAX(t.Amount) AS Amount
,SUM(CAST(t.TCount AS INT)) AS TransactionCount
,SUM(t.TotalAmount) AS TotalAmount
,SUM(ABS(t.TransactionCount)) AS TotalTrans
,ABS(MIN(t.TCount)) AS Voids
FROM c t
GROUP BY TransactionType
Again, not sure about some of the values provided.

T-SQL - How to use a recursive calculation in a CTE?

I want to calculate the avarage earnings per month of an employee during his time he worked for a company.
I build a recursive CTE based on a similar thread and I get the results only for one employee. What kind of modification do I need to do to make the employee ID variable and to get the same kind of results for every employee in the table?
Here is my code:
DECLARE #tbl AS TABLE
(
ID VARCHAR(50) ,
Earning FLOAT,
StartDate DATE ,
EndDate DATE
)INSERT INTO #tbl
( ID, Earning, StartDate, EndDate
SELECT employee_ID AS ID
,([Total Earning]/ (SELECT datediff(MONTH,[EndDate],
[StartDate])+1
FROM [employee_table] WHERE employee_ID = 'EKA-0004562'))
,[StarTDate]
,[EndDate]
FROM [employee_table]
WHERE employee_ID = 'EKA-0004562'
--final query using recursive cte
;
WITH cte
AS ( SELECT T.ID ,
T.Earning ,
T.StartDate ,
T.EndDatum ,
CONVERT(DATE, NULL) AS Dt ,
n = 0
FROM #tbl AS T
UNION ALL
SELECT cte.ID ,
cte.Earning ,
cte.StartDate ,
cte.EndDatum ,
DATEADD(MONTH, n, cte.StartDate) ,
cte.n + 1
FROM cte
WHERE n <= DATEDIFF(MONTH, cte.StartDate, cte.EndDatum)
)
SELECT cte.ID ,
cte.Earning,
dt AS Months
FROM cte
WHERE cte.Dt IS NOT NULL
This is my goal:
Well, I have a table with a lot of data with information concerning employees.
Every employee has a "startdate" (the time when he startet to work for the company) and and "enddate" (the time when he quit the job).
I would like to write into a table the same count of rows as the employee worked for the company in month. For example:
My basic table:
Employee Number | StartDate | EndDate | Total Earnings (Total Earnings/(EndDate-StartDate)
4711 20150101 20150523 24110
This example shows that the employee worked for the company for 5 Month and earned 24110€. In Avarage he earned 4822€ per month.
So I want to insert in the new table 5 rows with the following information:
New Table:
Employee Number | StartDate | EndDate | AVG Earnings
row1: 4711 20150101 20150523 4822
row2: 4711 20150201 20150523 4822
row3: 4711 20150301 20150523 4822
row4: 4711 20150401 20150523 4822
row5: 4711 20150501 20150523 4822
Here you go:
SAMPLE DATA
create table #test
(
ID INT,
StartDate DATE,
EndDatum DATE,
Earning INT
)
insert into #test values
(4711,'20150101','20150523',24110),
(4712,'20150101','20150625',32550)
QUERY
--final query using recursive cte
;
WITH cte
AS ( SELECT T.ID ,
T.Earning ,
T.StartDate ,
T.EndDatum ,
CONVERT(DATE, NULL) AS Dt ,
n = 0
FROM #test AS T
UNION ALL
SELECT cte.ID ,
cte.Earning ,
cte.StartDate ,
cte.EndDatum ,
DATEADD(MONTH, n, cte.StartDate) ,
cte.n + 1
FROM cte
WHERE n <= DATEDIFF(MONTH, cte.StartDate, cte.EndDatum)
)
SELECT cte.ID ,
dt StartDate,
cte.EndDatum EndDate,
cte.Earning / ((DATEDIFF(MONTH, cte.StartDate, cte.EndDatum)) +1) [AVG Earnings]
FROM cte
WHERE cte.Dt IS NOT NULL
OUTPUT
ID StartDate EndDate AVG Earnings
4712 2015-01-01 2015-06-25 5425
4712 2015-02-01 2015-06-25 5425
4712 2015-03-01 2015-06-25 5425
4712 2015-04-01 2015-06-25 5425
4712 2015-05-01 2015-06-25 5425
4712 2015-06-01 2015-06-25 5425
4711 2015-01-01 2015-05-23 4822
4711 2015-02-01 2015-05-23 4822
4711 2015-03-01 2015-05-23 4822
4711 2015-04-01 2015-05-23 4822
4711 2015-05-01 2015-05-23 4822
I may be wrong but I think your query seems overly complicated and the recursive CTE is not needed. It may be become inneficient when dealing with a lot of employees and consecutive years.
This query give the correct output for the 2 sample users:
Sample
declare #employee_table table(Employee_Number int, StartDate date, EndDate date, Total_Earnings bigint);
Insert Into #employee_table(Employee_Number, StartDate, EndDate, Total_Earnings) values
(4711, '20150101', '20150523', 24110)
, (4712, '20150101', '20150423', 24110);
Query
with list(n) as (
Select ROW_NUMBER() over(Order By n)
From (
Select 1 From (values(1), (1), (1), (1), (1), (1), (1), (1), (1), (1)) as l1(n)
Cross Join (values(1), (1), (1), (1), (1), (1), (1), (1), (1), (1)) as l2(n)
Cross Join (values(1), (1), (1), (1), (1), (1), (1), (1), (1), (1)) as l3(n)
) as l(n)
)
Select l.n, e.Employee_Number
, [StartDate] = DATEADD(MONTH, l.n-1, e.StartDate)
, [EndDate] = e.EndDate
, [AVG Earnings] = e.Total_Earnings/(DATEDIFF(MONTH, e.StartDate, e.EndDate)+1)
From #employee_table as e
Inner Join list as l on l.n <= DATEDIFF(MONTH, e.StartDate, e.EndDate)+1
Order By e.Employee_Number, l.n
Output
n Employee_Number StartDate EndDate AVG Earnings
1 4711 2015-01-01 2015-05-23 4822
2 4711 2015-02-01 2015-05-23 4822
3 4711 2015-03-01 2015-05-23 4822
4 4711 2015-04-01 2015-05-23 4822
5 4711 2015-05-01 2015-05-23 4822
1 4712 2015-01-01 2015-04-23 6027
2 4712 2015-02-01 2015-04-23 6027
3 4712 2015-03-01 2015-04-23 6027
4 4712 2015-04-01 2015-04-23 6027
notes:
#employee_table contains 2 employee. 4711 is similar to your sample
The list CTE efficiently creates a list from 1 to 1000 which should be good enough for 1000 months (> 83 years)
The main query uses it to create the list of consecutive months using just a simple INNER JOIN.

T-SQL: finding rows in a different table without joins

I have two tables, I'll call TableA and TableB
TableA:
StartNumber EndNumber Country
1 10 USA
11 20 USA
21 30 Canada
31 40 France
41 50 France
51 60 Germany
TableB:
SomeNumber
5
15
55
22
35
46
49
For each number in TableB, I want to find the corresponding row in TableA where the number is between the StartNumber and EndNumber and return the name of the country. I then want to group these results on the country column and return the number of times each country appears. So the results would look like this:
Country Occurrences
USA 2
Germany 1
Canada 1
France 3
Not sure how to do this.
Here the query.
Select A.Country, count(*) as Occurrences
from
tableA A
inner join
tableB B
on B.someNumber between a.startnumber and b.endnumber
group by A.country
This should do the trick (but does use a join):
declare #TableA table (StartNumber int, EndNumber int, Country varchar(16));
insert into #TableA (StartNumber, EndNumber, Country)
select 1, 10, 'USA' union
select 11, 20, 'USA' union
select 21, 30, 'Canada' union
select 31, 40, 'France' union
select 41, 50, 'France' union
select 51, 60, 'Germany';
declare #TableB table (SomeNumber int);
insert into #TableB (SomeNumber)
select 5 union
select 15 union
select 55 union
select 22 union
select 35 union
select 46 union
select 49;
select
a.Country, count(*) Occurrences
from
#TableA a inner join
#TableB b on b.SomeNumber between a.StartNumber and a.EndNumber
group by
a.Country;