SQL merge 3 tables - sql

I have an sql query involving 2 tables and try to add a third one.
These are the tables
FreeBookPos
FreeBooK_ID
ArticleNr
Amount
FreeBook
ID
BookNr
Date
FreeFields
FreeFieldType
Value
SQLPrimeKey
The first two are linked this way
select FreeBookPos.ArticleNr, Format(FreeBooking.Date, 'yyyy_MM') as dt,
SUM(CASE WHEN FreeBook.BookNr = 0 THEN FreeBookPos.Amount ELSE 0 END) as TotalEntryAmount,
SUM(CASE WHEN FreeBook.BookNr = 1 THEN FreeBookPos.Amount ELSE 0 END) as TotalLeftAmount
From FreeBookPos
INNER JOIN FreeBook on FreeBookPos.FreeBook_ID = FreeBook.ID
group by FORMAT ( FreeBook.Date, 'yyyy_MM'), FreeBookPos.ArticleNr
order by dt, ArticleNr
Now I need to add the table 3. This table is linked via SQLPrimeKey to FeeBook table ID. I then need to have only the fields where FreeFields.Value 2 or 4 and FreeFields.FreeFieldType = 54.
I tried various options with join but never get the result. Would I need to first join table 2 and 3 and then with 1 in a separate step?
Table 1: FreeBookPos
FreeBook_ID ArticleNr Amount
1 145 12
2 145 6
3 143 4
4 145 1
5 145 42
Table 2: FreeBook
ID BookNr Date
1 1 2012-05-19
2 -1 2012-05-21
3 1 2012-05-22
4 -1 2012-05-24
5 -1 2012-06-25
Table 3: FreeFields
SQLPrimareyKey FreeFieldType Value
1 54 1
2 52 2
3 54 4
4 54 2
5 54 2
Result should be:
ArticleNr Dt TotalEntryAmount TotalLeftAmount
143 2012-05 4 0
145 2012-05 0 -1
145 2012-06 0 -42

Try the below -
select FreeBookPos.ArticleNr, Format(FreeBooking.Date, 'yyyy_MM') as dt,
SUM(CASE WHEN FreeBook.BookNr = 0 THEN FreeBookPos.Amount ELSE 0 END) as TotalEntryAmount,
SUM(CASE WHEN FreeBook.BookNr = 1 THEN FreeBookPos.Amount ELSE 0 END) as TotalLeftAmount
From FreeBookPos
INNER JOIN FreeBook on FreeBookPos.FreeBook_ID = FreeBook.ID
inner join FreeFields on FreeBook.ID=SQLPrimareyKey
where value in (2,4) and FreeFieldType = 54
group by FORMAT ( FreeBook.Date, 'yyyy_MM'), FreeBookPos.ArticleNr
order by dt, ArticleNr

Related

How to do this in SQL (PostgreSQL Window Function?)

I have a situation in SQL (PostgreSQL specifically) that I'm struggling with. The schema/model that I'm working with is not under my control and not something I'm able to alter, so I am trying to figure out the best way to deal with the cards I've been dealt.
First, the schema, simplified for this question, but essentially it's invoice (Type = T) and transaction (Type <> T) lines combined into the same table. There can and will be n-number of tranaction lines per invoice and n-number of invoices per client.
Id
Type
InvoiceNo
ClientId
100
I
100
1
99
X
0
1
98
S
0
1
97
T
0
1
96
I
99
1
95
X
0
1
94
S
0
1
What I ultimately would like to end up with is something like the below, with the Invoice (Type = I) records removed and the Transaction (Type <> T) records that fall after each Invoice record populated with it's corresponding InvoiceId value.
Id
Type
InvoiceNo
ClientId
99
X
100
1
98
S
100
1
97
T
100
1
95
X
99
1
94
S
99
1
So far, the closest I've been able to get, which isn't very close, is using the below SQL:
select
t1.Id,
t1.Type,
t2.InvoiceNo,
t1.ClientId
from table AS t1
join (select
Id,
InvoiceNo,
ClientId
from table
where type = 'I') as t2
on t1.ClientId = t2.ClientId
where t1.ClientId = t2.ClientId and t1.Id <= t2.Id and t1.Type <> 'I'
The result of that looks something like the below, which works fine for the first invoice per client and then creates extra transaction records for each invoice
Id
Type
InvoiceNo
ClientId
99
X
100
1
98
S
100
1
97
T
100
1
95
X
100
1
95
X
99
1
94
S
100
1
94
S
99
1
Any help or guidance is much appreciated!
** Updated with more complex example **
Source:
Id
Type
InvoiceNo
ClientId
1
X
0
1
2
I
97
1
3
S
0
2
4
X
0
2
5
S
0
1
6
I
98
2
7
S
0
1
8
X
0
1
9
I
99
1
10
T
0
1
11
S
0
1
12
X
0
1
13
I
100
1
Playing with the answer below, I came up with:
select * from (select t.*,
max(InvoiceNo) filter (where type = 'I') over (partition by clientid order by id DESC) as imputed_invoiceno
from t) as x
where Type <> 'I';
Which gets me close:
Id
Type
InvoiceNo
ClientId
imputed_invoiceno
12
X
0
1
100
11
S
0
1
100
10
T
0
1
100
8
X
0
1
99
7
S
0
1
99
5
S
0
1
99
1
X
0
1
99
4
X
0
2
98
3
S
0
2
98
Best case result:
Id
Type
InvoiceNo
ClientId
12
X
100
1
11
S
100
1
10
T
100
1
8
X
99
1
7
S
99
1
5
S
99
1
1
X
97
1
4
X
98
2
3
S
98
2
Based on your sample data, you can use a cumulative window function:
select t.*,
min(invoiceno) filter (where type = 'I') over (order by id desc) as imputed_invoiceno
from t;

How to add a flag column based on column values and COUNT() of records partitioned by customer in SQL Server

My SQL Server table looks like this:
DayNo. Customer AgentsInvolved CallID DesiredFlag
-------------------------------------------------------
0 AAA 1 1858 0
0 AAA 3 1859 0
2 AAA 1 1860 0
0 BBB 2 1862 0
0 CCC 1 1863 1
0 DDD 3 1864 0
9 DDD 1 1865 0
9 DDD 4 1866 0
How do I add a new column to say;
WHEN (DayNo. = 0, and AgentsInvolved = 1) AND COUNT(callID) = 1 (grouped by customer)
THEN 1
ELSE 0
The column values I understand can be wrapped into a case statement but not sure how to add the condition for the COUNT(CallID). See the DesiredFlag column to see the result I'm trying to achieve.
Any help would be great.
I would use NOT EXISTS :
SELECT t.*,
(CASE WHEN NOT EXISTS (SELECT 1
FROM table t1
WHERE t1.Customer = t.Customer AND t1.CallID <> t.CallID
) AND t.DayNo = 0 AND t.AgentsInvolved = 1
THEN 1
ELSE 0
END) AS DesiredFlag
FROM table t;
with SAMPLE DATA:
declare #T Table (DayNo int,Customer varchar(10),AgentsInvolved int,CallID int)
insert into #T values
(0,'AAA',1,1858),
(0,'AAA',3,1859),
(2,'AAA',1,1860),
(0,'BBB',2,1862),
(0,'CCC',1,1863),
(0,'DDD',3,1864),
(9,'DDD',1,1865),
(9,'DDD',4,1866)
you can get your result (as i understand correctly) by:
;with summation as
(
select Customer, count(1) as qty
from #T
group by Customer
)
select
T.*,
coalesce(F.flag, 0) as flag
from
#T T
inner join summation s on s.Customer = T.Customer
outer apply (select 1 as flag where DayNo = 0 and AgentsInvolved = 1 and qty = 1) F
RESULTS:
DayNo Customer AgentsInvolved CallID flag
----------- ---------- -------------- ----------- -----------
0 AAA 1 1858 0
0 AAA 3 1859 0
2 AAA 1 1860 0
0 BBB 2 1862 0
0 CCC 1 1863 1
0 DDD 3 1864 0
9 DDD 1 1865 0
9 DDD 4 1866 0

Multiple times Grouping with where in SQL Server

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');

Summing Two Columns with a Join in SQL Server

I'm having a bit of issue trying to sum two column together with a left join - running in to grouping problems.
An example of the issue is below:
Table One: [Order]
ID CustomerID
1 512
2 317
3 562
Table Two: [OrderEntry]
OrderID Type ID QuantitySold QuantityReturned
1 A 1 1 0
1 A 2 3 0
1 A 3 1 1
2 A 4 1 1
3 B 5 2 0
What I'm trying to display:
CustomerID ID Sold - Returned
512 1 1
512 1 3
512 1 0
317 2 0
Where [OrderEntry].Type = 'A'
This is very basic SQL:
SELECT
ord.CustomerID
, ord.ID
, orden.QuantitySold - orden.QuantityReturned AS [Sold - Returned]
FROM Order ord
LEFT JOIN OrderEntry orden
ON ord.ID = orden.ID
WHERE orden.Type = 'A'
Here you can use any join as you are using and use concat function on two of your column like this
select concat(OrderEntry.QuantitySold, OrderEntry.QuantityReturned) AS newcolumn_name

SQL Query. limit an update per rows if condition is X and Y for the same ID number

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
);