Operation along the same column given a condition - sql

I have a list of amounts I want to add up for a particular currency code and display that total along with the underlying currency.
SOURCE TABLE TRANS
PORTCODE
AMOUNT
CCYTYPE
CCYCODE
BC100
40
DAC
DAC
BC100
30
DAC
DAC
BC100
30
DAC
DAC
BC100
35
ROPE
EUR
BC100
25
ROPE
EUR
BC100
25
ROPE
EUR
For example:
Select CCYCODE
FROM TRANS
WHEN CCYTYPE='ROPE'
OUTPUT
EUR
However, I am also using the CCYTYPE='DAC' to perform a calculation such as:
SELECT
T.PORTCODE,
T.ID,
T.VAN = sum(amount)
FROM TRANS T
INNER JOIN METRIC M
ON T.METRICCODE=M.METRICCODE
WHERE 1=1
AND T.CCYTYPE='DAC'
The sum is comprised of several hundred amounts in the TRANS table.
OUTPUT
PORTCODE | ID | VAN | CCYCODE
BC100 | 31 | 100 | EUR
How can I get the result of the ccytype, portcode, ID, and VAN to appear together with these two distinct conditions?

The syntax in the two individual queries is incorrect. But assuming it is correct, you can put each individual query in a subquery and join it like it were a table.
Assuming what is common between query 1 and query 2 is PORTCODE you can do the following:
SELECT
a.*
,b.CCYCODE
FROM
(SELECT
T.PORTCODE,
T.ID,
sum(amount) AS VAN
FROM TRANS T
INNER JOIN METRIC M
ON T.METRICCODE=M.METRICCODE
WHERE
1=1
AND T.CCYTYPE='DAC'
GROUP BY
T.PORTCODE,
T.ID
) AS a
LEFT JOIN
(Select
PORTCODE
,CCYCODE
FROM TRANS
WHEN CCYTYPE='ROPE'
) AS b
ON a.PORTCODE = b.PORTCODE

Related

SQL Joining One Table to a Selection of Rows from Second Table that Contains a Max Value per Group

I have a table of Cases with info like the following -
ID
CaseName
Date
Occupation
11
John
2020-01-01
Joiner
12
Mark
2019-10-10
Mechanic
And a table of Financial information like the following -
ID
CaseID
Date
Value
1
11
2020-01-01
1,000
2
11
2020-02-03
2,000
3
12
2019-10-10
3,000
4
12
2019-12-25
4,000
What I need to produce is a list of Cases including details of the most recent Financial value, for example -
ID
CaseName
Occupation
Lastest Value
11
John
Joiner
2,000
12
Mark
Mechanic
4,000
Now I can join my tables easy enough with -
SELECT *
FROM Cases AS c
LEFT JOIN Financial AS f ON f.CaseID = c.ID
And I can find the most recent date per case from the financial table with -
SELECT CaseID, MAX(Date) AS LastDate
FROM Financial
GROUP BY CaseID
But I am struggling to find a way to bring these two together to produce the required results as per the table set out above.
A simple method is window functions:
SELECT *
FROM Cases c LEFT JOIN
(SELECT f.*, MAX(date) OVER (PARTITION BY CaseId) as max_date
FROM Financial f
) f
ON f.CaseID = c.ID AND f.max_date = f.date;

New to SQL - How to compare data from two sets of joined tables

I'm trying to compare a set of multiple tables against another set of multiple tables in a SQL database. Admittedly, I'm very novice to SQL so please forgive me if my terminology is incorrect.
I have 6 individual tables in my database. 3 of those are comprised of current month's data and the other three are prior month's data. I need to produce a report that shows current month data, but also compare the account balance against the prior month - I need to create a column that will list "true" or "false" based on whether the account balances match.
I have joined the three current month's data tables together and I have joined the three prior month's data tables together.
The two sets of tables are identical. Below is a description of the tables - There is one set prefixed "CURRENT" and one prefixed "PRIOR":
BALANCE:
EntityID
AccountID
AccountBalance
ENTITY:
ID
Label
Description
ACCOUNT:
ID
AccountNumber
Description
The report I need to provide should list the following from the current month's data:
Label
Description
AccountNumber
AccountDescription
AccountBalance
I need to add a column called "Changed" at the end of the report. This column should have a "True" or "False" value depending on whether or not the current & prior account balances match.
Thus far, I have only been able to join the tables. I'm unsure how to edit this query to compare the current month dbo.CURRENT_BALANCE.AccountBalance against the prior month's dbo.PRIOR_BALANCE.AccountBalance
SELECT DISTINCT
dbo.CURRENT_ENTITY.Label,
dbo.CURRENT_ENTITY.Description AS Entity,
dbo.CURRENT_ACCOUNT.AccountNumber,
dbo.CURRENT_ACCOUNT.Description AS AccountDescription,
dbo.CURRENT_BALANCE.GLAccountBalance
FROM
dbo.CURRENT_BALANCE
INNER JOIN dbo.CURRENT_ENTITY ON dbo.CURRENT_BALANCE.EntityID = dbo.CURRENT_ENTITY.ID
INNER JOIN dbo.CURRENT_ACCOUNT ON dbo.CURRENT_BALANCE.AccountID = dbo.CURRENT_ACCOUNT.ID
CROSS JOIN dbo.PRIOR_BALANCE
INNER JOIN dbo.PRIOR_ENTITY ON dbo.PRIOR_BALANCE.EntityID = dbo.PRIOR_ENTITY.ID
INNER JOIN dbo.PRIOR_ACCOUNT ON dbo.PRIOR_BALANCE.AccountID = dbo.PRIOR_ACCOUNT.ID
The query above returns my expected results:
Label Entity AccountNumber AccountDescription AccountBalance
21 Company ABC 1 Customer Sales 25
21 Company ABC 2 Customer Sales 568
22 XYZ Solutions 3 Vendor Sales 344
23 Number 1 Products 4 Vendor Sales 565
24 Enterprise Inc 5 Wholesale 334
24 Enterprise Inc 6 Wholesale 5452
24 Enterprise Inc 7 Wholesale 5877
26 QWERTY Solutions 8 Customer Sales 456
27 Acme 9 Customer Sales 752
28 United Product Solutions 10 Vendor Sales 87
What I would like to do is have a result similar to:
Label Entity AccountNumber AccountDescription AccountBalance Changed
21 Company ABC 1 Customer Sales 25 FALSE
21 Company ABC 2 Customer Sales 568 FALSE
22 XYZ Solutions 3 Vendor Sales 344 FALSE
23 Number 1 Products 4 Vendor Sales 565 FALSE
24 Enterprise Inc 5 Wholesale 334 TRUE
24 Enterprise Inc 6 Wholesale 5452 FALSE
24 Enterprise Inc 7 Wholesale 5877 TRUE
26 QWERTY Solutions 8 Customer Sales 456 FALSE
27 Acme 9 Customer Sales 752 FALSE
28 United Product Solutions 10 Vendor Sales 87 FALSE
I have no idea where to go from here. Would appreciate any advise from this group!
The below should work as a way to compare the 2 values.
I have added aliases to table names to help with reading;
SELECT DISTINCT
ce.Label
,ce.Description AS Entity
,ca.AccountNumber
,ca.Description AS AccountDescription
,cb.GLAccountBalance
,CASE
WHEN cb.GLAccountBalance = p.PriorBalance THEN 'False'
WHEN cb.GLAccountBalance <> p.PriorBalance THEN 'True'
END AS [Changed]
FROM dbo.CURRENT_BALANCE cb
INNER JOIN dbo.CURRENT_ENTITY ce ON cb.EntityID = ce.ID
INNER JOIN dbo.CURRENT_ACCOUNT ca ON cb.AccountID = ca.ID
LEFT JOIN ( SELECT DISTINCT
pe.ID AS PE_ID
,pa.ID AS PA_ID
,pb.GLAccountBalance AS PriorBalance
FROM dbo.PRIOR_BALANCE pb
INNER JOIN dbo.PRIOR_ENTITY pe ON pb.EntityID = pe.ID
INNER JOIN dbo.PRIOR_ACCOUNT pa ON pb.AccountID = pa.ID
) p ON p.PE_ID = ce.ID AND p.PA_ID = ca.ID

SELECT with LEFT JOIN performing math operation twice?

The general idea of what I'm trying to do is this:
Select all planned prices for an order, then subtract from that total all actual prices on that order.
The planned price and actual price are on different tables. When I have a single planned price and a single actual price, this works fine. However, when I have multiple planned prices or multiple actual prices it is giving me odd results as if the algebra is happening multiple times.
Query:
SELECT PL.orderid, (SUM(PL.lineprice) - NVL(SUM(AC.lineprice),0)) AS
Difference FROM plans PL
LEFT JOIN actuals AC ON PL.orderid = AC.orderid
WHERE PL.customer IN (SELECT customer FROM ...)
GROUP BY PL.orderid
ORDER BY PL.orderid;
The results of the query:
Orderid Difference
X-1224 100
X-1226 80
X-1345 70000
X-1351 125000
X-1352 10000
Y-2403 190000
My Plan table looks like this:
Orderid Planned_Price
X-1224 100
X-1226 100
X-1345 105000
X-1351 100000
X-1352 10000
X-1352 50000
Y-2403 25000
Y-2403 100000
And my Actual table this:
Orderid Actual_Price
X-1226 20
X-1345 35000
X-1351 25000
X-1351 50000
X-1352 25000
Y-2403 25000
Y-2403 5000
So it seems to work when I have only a single row in each table, or a single row in plans and no rows in actuals i.e., X-1224, X-1226 and X-1345.
However the results are too high or too low when I have multiple rows, with the same OrderID, in either table i.e., all the rest
I'm stumped as to why this is the case. Any insights are appreciated.
edit: Results I'd like, taking Y-2403 as example: (25000 + 100000) - (25000 + 5000) = 95000. What I'm getting is double that at 190000.
Why is this the case?
Because that is how join works. If you have data like this:
a
1
1
2
2
And b:
b
1
1
1
2
Then the result of a join will have six "1"s and two "2"s.
Your question doesn't say what you want for results, but a typical approach is to aggregate before doing the joins.
EDIT:
You seem to want:
select p.orderid,
(p.lineprice - coalesce(lineprice, 0)) as Difference
from (select orderid, sum(lineprice) as lineprice
from plans p
group by orderid
) p left join
(select orderid, sum(lineprice) as lineprice
from actuals a
group by orderid
) a
on p.orderid = a.orderid
where p.customer in (SELECT customer FROM ...)
order by p.orderid;
I suppose you are looking to compare the summed_up_prices by order id of plan table with the summed_up prices by order id actual plan table.?
If so the following can be done to ensure there are no duplicates entries by order
select a.orderid
,NVL(max(b.summed_up),0) - sum(a.actual_price) as difference
from actual_table a
left join (select pt.orderid
,sum(pt.planned_price) as summed_up
from planned_table pt
group by pt.orderid
)b
on a.orderid=b.orderid
group by a.orderid
+---------+------------+
| ORDERID | DIFFERENCE |
+---------+------------+
| X-1226 | 80 |
| Y-2403 | 95000 |
| X-1351 | 25000 |
| X-1345 | 70000 |
| X-1352 | 35000 |
+---------+------------+
Here is the dbfiddle link with the data
https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=3cacffd19b39ecaf7ad752dff262ac47

Writing a Query with Distinct Count in Access

I'm having some difficulty with a query that I'm writing that is meant to display the "makers" that produce laptops with 3 or more DIFFERENT speeds.
SELECT DISTINCT Product.maker, Count(Laptop.speed) AS [3+ Different Speeds]
FROM Laptop INNER JOIN Product ON Laptop.model = Product.model
WHERE type = "laptop"
GROUP BY Product.maker
HAVING Count(*) >= 3;
This gives me the 2 correct "makers" that produce 3 or more laptop models, however, one "maker", A, produces two laptop models with the SAME speed, so that "maker" needs to be eliminated from the resulting table, which is below.
maker 3+ Different Speeds
A 3
E 3
Here's the Laptop table where the model and speed data is stored:
model speed
2001 2.00 E
2002 1.73 E
2003 1.80 E
2004 2.00 A
2005 2.16 A
2006 2.00 A
E produces the top 3, and A produces the bottom 3. I'm fairly certain that I need to make my Count function DISTINCT, however, I know that Access does not support DISTINCT Count. Any assistance/suggestions would be greatly appreciated!
The below query should solve your problem.
SELECT
maker,
COUNT(speed)
FROM(
SELECT
p.maker,
l.speed
FROM
Laptop l
INNER JOIN Product p
ON l.model = p.model
WHERE
type = "laptop"
GROUP BY 1,2
) foo
GROUP BY 1
HAVING COUNT(1) >= 3
First you aggregate all speeds for the same maker, so the inner query would produce:
maker | speed | count
-------+-------+-------
E | 1.73 | 1
E | 1.80 | 1
A | 2.16 | 1
E | 2.00 | 1
A | 2.00 | 2
Now you have distinct rows for each pair (maker, speed) so that you can simply run a COUNT() over speed.
Result
maker | count
-------+-------
E | 3
A | 2
Now eliminate A with HAVING clause.
Your query will work fine if you take out the distinct keyword. If you only group by the maker, then that query will bring you back only one record per maker, the distinct is actually redundant.
This is the WORKING query that I came up with, a slightly modified version of what you provided me with.
SELECT P.maker AS [Maker], Count(L.speed) AS [3+ Different Speeds]
FROM (SELECT P.maker, L.speed FROM Laptop AS L INNER JOIN Product AS P ON L.model = P.model
WHERE type = "laptop"
GROUP BY P.maker, L.speed)
GROUP BY [Maker]
HAVING Count(L.speed) >= 3;
Thanks again!

SQL multiple 1-to-many joins

I'm almost certain I've run into this before and am just having an extended senior moment, but I am trying to pull work order data from three different tables across 2 db's on a SQL instance and combine it all into a report, I'm looking for the end result to contain the following columns:
WO | Production Recorded Qty | Inventory Qty | Variance
The Variance part is easy I can just nest the select statement, and subtract the two quantities in the outer statement, but the problem I'm running in to is when I join the production and Inventory tables in their corresponding databases I end up getting sums of the columns that I'm targeting that are way larger than what they should be
Sample Data:
Work Order, Short P/N, and Long P/N in Work Order Table:
dba.1
WO ShortPN LongPN
152 1234 Part1
Short P/N, Quantity on hand, location, and lot # in inventory table:
dba.2
ShortPN Qty Loc Lot
1234 31 Loc1 456
1234 0 Loc2 456
1234 0 Loc4 456
1234 19 Loc1 789
1234 25 Loc4 789
Work Order, Long P/N, and production count of the last 5min in Production table:
dbb.3
WO LongPN Count
152 Part3 6
152 Part3 8
152 Part3 9
152 Part3 4
152 Part3 6
152 Part3 7
With this example I've tried:
SELECT 1.WO AS WO
,SUM(2.Qty) AS "Qty On Hand"
,SUM(3.Count) AS "Produced Qty"
FROM dba.1
INNER JOIN dbb.2 ON 1.ShortPN=2.ShortPN
INNER JOIN dbb.3 ON 1.WO = 3.WO
GROUP BY 1.WO
I've also tried selecting from 3, joining 1 to 3 on the WO, then 2 to 1 on shortPN, and both yield SUM() numbers that are exponentially higher than they should be(ie what should be 15,xxx turns into over 2,000,000), however if I remove one of the data points from the report and select just the inventory or production qty I get the correct end results. I swear that I've run into this before but for the life of me can't remember how it was solved, sorry if it's a duplicate question as well, couldn't find anything by searching.
Thanks in advance for the help, it's greatly appreciated.
You can do something like this
select
WO.WO, isnull(i.Qty, 0) as Qty, isnull(p.[Count], 0) as [Count]
from WorkOrder as WO
left outer join (select t.ShortPN, sum(t.Qty) as Qty from inventory as t group by t.ShortPN) as i on
i.ShortPN = WO.ShortPN
left outer join (select t.WO, sum(t.[Count]) as [Count] from Production as t group by t.WO) as p on
p.WO = WO.WO
SQL FIDDLE example
if you have SQL Server 2005 or higher, you can write it like this
select
WO.WO, isnull(i.Qty, 0) as Qty, isnull(p.[Count], 0) as [Count]
from WorkOrder as WO
outer apply (select sum(t.Qty) as Qty from inventory as t where t.ShortPN = WO.ShortPN) as i
outer apply (select sum(t.[Count]) as [Count] from Production as t where t.WO = WO.WO) as p
SQL FIDDLE example
this happens because when you make a join of WO and inventory tables you got
WO SHORTPN QTY
-------------------
152 1234 31
152 1234 0
152 1234 0
152 1234 19
152 1234 25
and you see that now you have 5 rows with WO = 152. When you add join with Production table, for each row with WO = 152 from this join there will be 6 rows with WO = 152 from Production table, so you will have 30 rows total and QTY from inventory will be listed 6 times each. When you sum this up, instead of 75 you will have 75 * 6 = 450. And for Count you'll have each Count * 5, so instead of 40 you'll have 200.