I am writing a data fix SQL script that is to insert a new record using data from two rows that are under the same ID.
My table looks like the following:
AccountID | ActivityId | Debit | Credit | DisplayDetails | TransactionDate
=========================================================================
1 1 100 0 Display Details1 2015-02-02
1 2 0 0 Display Details1 2018-02-02
1 1 300 0 Display Details1 1999-02-02
1 2 0 0 Display Details1 2000-02-02
2 1 200 0 Display Details2 2017-02-02
2 2 0 0 Display Details2 2017-04-06
2 12 0 200 Display Details2 2015-04-06
3 1 200 0 Display Details3 2015-02-04
3 3 0 200 Display Details3 2015-06-02
4 1 100 0 Display Details4 2016-02-02
4 2 0 0 Display Details4 2016-06-02
ActivityId 1 writes to Debit
ActivityId 2 writes to neither, but is needed in my conditions
ActivityId 3 writes to Credit
ActivityId 12 writes to Credit
My data fix is to find ActivityId 1 with an associated ActivityId 2 but NOT an associated 12 or 3 under the same AccountID.
I have written a query that meets these conditions:
SELECT A.AccountID
INTO #temp
FROM Account A WITH(NOLOCK)
WHERE ActivityId IN (1, 2, 3, 12)
GROUP BY A.AccountID
HAVING SUM(CASE WHEN A.ActivityId = 1 THEN 1 ELSE 0 END) > 0 AND
SUM(CASE WHEN A.ActivityId = 2 THEN 1 ELSE 0 END) > 0 AND
SUM(CASE WHEN A.ActivityId = 3 THEN 1 ELSE 0 END) = 0 AND
SUM(CASE WHEN A.ActivityId = 12 THEN 1 ELSE 0 END) = 0;
Now that I have the affected data, I need to insert a new record with ActivityId 12 using DisplayDetails from the associated Accounts ActivityId 2 and TransactionDate from ActivityId 1.
I also need to insert to field Credit using the Debit value from ActivityId 1.
The background behind this is each Activity 1 and 2 under the same AccountId SHOULD have an ActivityId 12 too, however some of these were missed, hence the need for this fix script.
Below is my approach:
-- Uses AccountIds retrieved above to then get data from parent table.
SELECT A.AccountID, A.ActivityId, A.DebitAmount, A.CreditAmount, A.DisplayDetails, A.TransactionDate
INTO #temp2
FROM Account A
JOIN #temp T
ON T.AccountID = A.AccountID
-- Get ActivityId 2 data
SELECT *
INTO #ActivityTwo
FROM #temp2 T
WHERE T.ActivityId = 2
INSERT INTO Account (AccountID, ActivityId, DebitAmount, CreditAmount, DisplayDetails, TransactionDate)
SELECT T.AccountID, 12, 0, T.DebitAmount, S.DisplayDetails, T.TransactionDate
FROM #temp2 T WITH(NOLOCK)
JOIN #ActivityTwo S
ON T.AccountID = S.AccountID
WHERE T.ActivityId = 1
However if I have multiple Activity 1 and Activity 2 under the same AccountId, my script inserts duplicate rows.
AccountID | ActivityId | Debit | Credit | DisplayDetails | TransactionDate
=========================================================================
1 1 100 0 Display Details1 2015-02-02
1 2 0 0 Display Details1 2018-02-02
1 1 300 0 Display Details1 1999-02-02
1 2 0 0 Display Details1 2000-02-02
1 12 0 100 Display Details1 2015-02-02
1 12 0 100 Display Details1 2015-02-02
1 12 0 300 Display Details1 1999-02-02
1 12 0 300 Display Details1 1999-02-02
2 1 200 0 Display Details2 2017-02-02
2 2 0 0 Display Details2 2017-04-06
2 12 0 200 Display Details2 2015-04-06
3 1 200 0 Display Details3 2015-02-04
3 3 0 200 Display Details3 2015-06-02
4 1 100 0 Display Details4 2016-02-02
4 2 0 0 Display Details4 2016-06-02
4 12 0 100 Display Details4 2016-02-02
As you can see, AccountID 1 has 4 extra 12 records, when it should only have two 12 records.
AccountID 4 worked correctly though, so I believe the problem lies with an account having multiple ActivityId 1 and 2s.
Why is this happening? What can I do to fix this?
Does anyone have a better approach to this problem?
Any help would be greatly appreciated.
Thanks!
Since you do not have any way to associate Activity 1 rows with Activity 2 rows, I think you need a SELECT DISTINCT on your second insert.
SELECT DISTINCT A.AccountID, A.ActivityId, A.DebitAmount, A.CreditAmount,
A.DisplayDetails, A.TransactionDate
INTO #temp2
FROM Account A
JOIN #temp T
ON T.AccountID = A.AccountID
Related
I have two tables which I can generate with SELECT statements (joining multiple tables) as follows:
Table 1:
ID
Site
type
time
1
Dallas
2
01-01-2021
2
Denver
1
02-01-2021
3
Chicago
1
03-01-2021
4
Chicago
2
29-11-2020
5
Denver
1
28-02-2020
6
Toronto
2
11-05-2019
Table 2:
ID
Site
collected
deposited
1
Denver
NULL
29-01-2021
2
Denver
01-04-2021
29-01-2021
3
Chicago
NULL
19-01-2020
4
Dallas
NULL
29-01-2019
5
Winnipeg
13-02-2021
17-01-2021
6
Toronto
14-02-2020
29-01-2020
I would like the result to be grouped by Site, having on each column the COUNT of type=1 , type=2, deposited and collected, all of the 4 columns between a selected time interval. Example: (interval between 01-06-2020 and 01-06-2021:
Site
type1
type2
deposited
collected
Dallas
0
1
0
0
Denver
1
0
2
1
Chicago
1
1
0
0
Toronto
0
0
0
0
Winnipeg
0
0
1
1
How about union all and aggregation?
select site,
sum(case when type = 1 then 1 else 0 end) as type_1,
sum(case when type = 2 then 1 else 0 end) as type_2,
sum(deposited) as deposited, sum(collected) as collected
from ((select site, type, 0 as deposited, 0 as collected
from table1
) union all
(select site, null,
(case when deposited is not null then 1 else 0 end),
(case when collected is not null then 1 else 0 end)
from table2
)
) t12
group by site;
Combine your tables 1 and 2 with a join on Site
Use COUNT(CASE WHEN type = 1 then 1 END) as type1 and a similar construct for type 2
Use COUNT(CASE WHEN somedate BETWEEN '2020-06-01' and '2021-06-01' then 1 END) as ... for your dates
I have a source table like this
ProductName SaleReceipt SaleCode
--------------------------------
F-Apple 1001 1
F-Orange 1002 2
G-Rice 1003 3
G-Barile 1005 4
G-Oats 1006 1
V-Carrot 1007 4
V-Cabbage 1008 3
V-Potato 1009 1
V-Tomato 1010 1
Chocolate 1011 4
Cookies 1012 1
Cakes 1013 2
I need to create a report like this
30 Day delay 60 Day Delay 90 day delay 120 day delay
Fruits 1 1 0 0
Grains 1 0 1 1
Vegetables 2 0 1 1
Other category 1 1 0 1
The conditions to create the report are:
All ProductName start with F is grouped as fruits
All ProductName start with G is grouped as Grains
All ProductName start with V is grouped as Vegetables
Other product name go in the other category
30 day delay: count of (SaleReceipt) with a SaleCode=1
60 day delay: count of (SaleReceipt) with a SaleCode=2
90 day delay: count of (SaleReceipt) with a SaleCode=3
120 day delay: count of (SaleReceipt) with a SaleCode>=4
I could not find how to do grouping two times. I am using SQL Server 2014.
You can use case in a group by. Or use a lookup table:
select coalesce(c.name, 'Other category'),
sum(case when salescode = 1 then 1 else 0 end) as salecode_1,
sum(case when salescode = 2 then 1 else 0 end) as salecode_2,
sum(case when salescode = 3 then 1 else 0 end) as salecode_3,
sum(case when salescode = 4 then 1 else 0 end) as salecode_4
from t left join
(values ('F-%', 'Fruit'), ('G-%' , 'Grain'), ('V-%', 'Vegetable')
) c(pattern, name)
on t.productname like c.pattern
group by coalesce(c.name, 'Other category');
Have the following table tblTrans where
Trans_ID Trans Sequence Trans_PointsEarned Trans_PointsApplied
4452 1 1 1
4452 2 1 1
4452 3 0 1
4462 1 1 1
4462 2 1 1
4462 3 1 1
4462 4 1 1
4462 5 1 1
9101 1 0 1
9101 2 0 1
9101 3 0 1
9101 4 0 1
(useless table doesnt work)
I need to set the following on another field per every customer ID.
So Customer_OverallPoints
4452 = 2 (doesn't count 0's)
4462 = 4 (I want to cap the points to 4 based on the sequence and transID and customerID)
9101 = 0 (dont count 0's).
This needs to be applied to thousands of records based on customerID and TransID where Trans_Sequence is within the same Trans_ID and it only counts the first 4 rows that have the Trans_pointsEarned = 1.
I tried putting a psuedocode together but it just looked ridicilous and I can't even come up with the logic for this.
Thanks
Assuming that TransId is really the customer id, I think the basic logic is just an aggregation:
select t.TransId,
(case when sum(t.Trans_PointsEarned) > 4 then 4
else sum(t.Trans_PointsEarned)
end) as Customer_OverallPoints
from tblTrans t
group by t.TransId;
You can put this into an update statement as:
update customers c
set Customer_OverallPoints = (select (case when sum(t.Trans_PointsEarned) > 4 then 4
else sum(t.Trans_PointsEarned)
end)
from tblTrans t
where t.TransId = c.CustomerId
);
I have the table below
ID | PARCEL | STATUS | ORDER_ID
1 1 PENDING 1234
2 2 COMPLETE 1234
3 1 COMPLETE 9999
4 2 PENDING 9999
5 3 PENDING 9999
6 1 COMPLETE 1111
7 2 COMPLETE 1111
8 3 COMPLETE 1111
9 1 COMPLETE 3333
10 2 PENDING 3333
i need get results when the first parcel is PENDING and have more than one parcel.
i try with the sql:
SELECT * FROM table WHERE parcela = 1 AND status = 'pending'
group by order_id
having count(order_id) > 1
the answer for the query is:
ID | PARCEL | STATUS | ORDER_ID
1 1 PENDING 1234
2 2 COMPLETE 1234
You can get the orders using a having clause:
select order_id
from table
group by order_id
having count(order_id) > 1 AND
sum(case when parcela = 1 AND status = 'pending' then 1 else 0 end) > 0;
If you want the details, join the rows from the table back in on the order_id.
The problem with your query is that you are using a filter in the where clause that limits the rows to only the first row. This prevents the query from counting the total number of rows in each order.
I have 2 tables(Product1, product2).
Product1 Product2
------------------------------ -------------------------------------
PID ProdDesc ProdCode Date PID
------------------------------ -------------------------------------
1 Sony s001 2013/01/21 1
2 Samsung sa01 2013/02/27 1
3 LG L001 2013/03/14 2
4 Toshiba T001 2013/04/18 3
5 Philips P001 2013/05/30 4
2013/06/12 5
I need to generate a query that joins the data from the 2 tables and groups the results by month.
Here is my desired Output:
ProdDesc Jan2013 Feb2013 Mar2013 Apr2013 May2013 Jun2013 Jul2013 Aug2013 Sep2013 Oct2013 Nov2013 Dec2013
--------------------------------------------------------------------------------------------------
Sony 1 1 0 0 0 0 0 0 0
Samsung 0 0 1 0 0 0 0 0 0
LG 0 0 0 1 0 0 0 0 0
Toshiba 0 0 0 0 1 0 0 0 0
Philips 0 0 0 0 0 1 0 0 0
You'll need to use a PIVOT to project your result in columns, although some manipulation is required to prepare the data beforehand, to generate your column names and group data per month:
SELECT ProdDesc, [Jan2013],[Feb2013],[Mar2013],[Apr2013],
[May2013],[Jun2013]
FROM
(
SELECT ProdDesc, YearMonth, COUNT(P2PID) AS ProdCount
FROM
(
SELECT p1.ProdDesc,
CAST(DATENAME(MONTH, [DATE]) AS VARCHAR(3)) +
DATENAME(YEAR, [DATE]) AS YearMonth,
p2.PID as P2PID
FROM Product1 p1
LEFT JOIN Product2 p2
ON p1.PID = p2.PID
) x
GROUP BY ProdDesc, YearMonth
) y
PIVOT
(
SUM(ProdCount)
for [YearMonth] IN ([Jan2013],[Feb2013],[Mar2013],
[Apr2013],[May2013],[Jun2013])
) pv;
SqlFiddle here
It is quite likely that you'll want to determine the columns (MonYYYY) dynamically. Have a look here on how to do this.
You can use ISNULL or COALESCE to replace NULLS in the output, if necessary ISNULL([Jan2013], 0) AS Jan2013