Group on ID, and sum from different table (3 table total) - sql

I have three tables,
Name - columns
Custpackingslipjour(table 1) - (deliverydate, dateclosed,, salesid)
Inventrans (Table 2) - (itemid, datephysical, transrefid)
Salesline (Table 3) - (lineamount, itemid, salesid
What i need is a single table containing all three tables, but without redundant information such as multiple of the same salesids, and with a total sum (salesline.lineamount) and where i can elminate results based on deliverydate and closed date, along with datephysical, originally i had this.
SELECT TOP (10) dbo.AX_CUSTPACKINGSLIPJOUR.DELIVERYDATE,
dbo.AX_SALESLINE.LINEAMOUNT, dbo.AX_INVENTTRANS.DATEPHYSICAL,
dbo.AX_INVENTTRANS.COSTAMOUNTPOSTED, dbo.AX_INVENTTRANS.ITEMID,
dbo.AX_INVENTTRANS.TRANSREFID, dbo.AX_CUSTPACKINGSLIPJOUR.SALESID
FROM dbo.AX_CUSTPACKINGSLIPJOUR
INNER JOIN
dbo.AX_SALESLINE ON dbo.AX_CUSTPACKINGSLIPJOUR.SALESID = dbo.AX_SALESLINE.SALESID
INNER JOIN
dbo.AX_INVENTTRANS ON dbo.AX_SALESLINE.ITEMID = dbo.AX_INVENTTRANS.ITEMID
But it produces a table with many of the same lines, because of the inherent one-to-many relationship between salesid and itemid.
So I thought i would group the sum of the value of the items associated with each salesid as that is what I am after.
Based on a few other posts on here, I tried combining the sum of lineamount from salesline by grouping it on salesid, but after 5 minutes of running, it did not appear to be a good solution, I think i have the right idea, but I am doing it wrong.
select top 10 s.SALESID,
SUM(sp.LINEAMOUNT) as 'TotalLineamount'
from AX_CUSTPACKINGSLIPJOUR as s
right outer join AX_SALESLINE as sp on s.SALESID=sp.SALESID
left outer join AX_INVENTTRANS as p on sp.ITEMID=p.ITEMID
where s.SALESID is not null
group by s.SALESID,sp.LINEAMOUNT
Any help is greatly appreciated and I will follow up any questions or comments if what I am trying to do is unclear.
Edit: Following #coltech's advice and trying with distinct on the salesid, did not work, but it was tested. I inserted the distinct(salesid) after the top 10
Edit: Following Gavins advice, i changed to
select top 10 cp.SALESID,
SUM(sl.LINEAMOUNT) as 'TotalLineamount'
from AX_CUSTPACKINGSLIPJOUR as cp
right outer join AX_SALESLINE as sl on cp.SALESID=sl.SALESID
left outer join AX_INVENTTRANS as it on sl.ITEMID=it.ITEMID
where cp.SALESID is not null
group by cp.SALESID
I also changed the prefixes for the tables to better match the table names. This works, however if I want to include more columns, for instance.
sl.LINEAMOUNT, it.DATEPHYSICAL, it.COSTAMOUNTPOSTED, it.ITEMID, it.TRANSREFID and cp.SALESID
then I will have to include these in the group by, as such.
select top 10 cp.SALESID,
SUM(sl.LINEAMOUNT) as 'TotalLineamount',
cp.DELIVERYDATE,
sl.LINEAMOUNT, it.DATEPHYSICAL,
it.COSTAMOUNTPOSTED, it.ITEMID,
it.TRANSREFID, cp.SALESID
from AX_CUSTPACKINGSLIPJOUR as cp
right outer join AX_SALESLINE as sl on cp.SALESID=sl.SALESID
left outer join AX_INVENTTRANS as it on sl.ITEMID=it.ITEMID
where cp.SALESID is not null
group by cp.SALESID, cp.DELIVERYDATE,sl.LINEAMOUNT, it.DATEPHYSICAL, it.COSTAMOUNTPOSTED, it.ITEMID, it.transrefid
However, this appears to cause the query to run for a very long time, been running for close to 25 mins. Is there a way to speed this up? Or am I just tackling this incorrectly?

I think you're fine except you shouldn't sum on the column you want to group by, so just do this instead:
select top 10 s.SALESID,
SUM(sp.LINEAMOUNT) as 'TotalLineamount'
from AX_CUSTPACKINGSLIPJOUR as s
right outer join AX_SALESLINE as sp on s.SALESID=sp.SALESID
left outer join AX_INVENTTRANS as p on sp.ITEMID=p.ITEMID
where s.SALESID is not null
group by s.SALESID

Related

How do I get all values for Store_ID pulled into my Snowflake Query?

I have a query below and am trying to get all the week_id's, upc_id's and upc_dsc's pulled in even if there is no net_amt or item_qty for them. I'm successfully pulling in all stores, but I also want to show a upc and week id for these stores so that they can see if they have 0 sales for a upc. I tried doing a right join with my date table under the right join of the s table as well as a right join for the upc table, but it messes up my data and doesn't pull in the columns I need. Does anyone know how to fix this?
Thank you
select
a.week_id
, s.district_cd
, s.store_id
, a.upc_id
, a.upc_dsc
, sum(a.net_amt) as current_week_sales
, sum(t.net_amt) as last_week_sales
, sum(a.item_qty) as current_week_units
, sum(t.item_qty) as last_week_units
from (
select
week_id
, district_cd
, str.store_id
, txn.upc_id
, upc_dsc
, dense_rank() over (order by week_id) as rank
, sum(txn.net_amt) as net_amt
, sum(txn.item_qty) as item_qty
from dw_dss.txn_facts txn
left join dw_dss.lu_store_finance_om STR
on str.store_id = txn.store_id
join dw_dss.lu_upc upc
on upc.upc_id = txn.upc_id
join lu_day_merge day
on day.d_date = txn.txn_dte
where district_cd in (72,73)
and txn.upc_id in (27610100000
,27610200000
,27610300000
,27610400000
)
and division_id = 19
and txn_dte between '2021-07-25' and current_date - 1
group by 1,2,3,4,5
) a
left join temp_tables.ab_week_ago t
on t.rank = a.rank and a.store_id = t.store_id and a.upc_id = t.upc_id
right join dw_dss.lu_store_finance_om s
on s.store_id = a.store_id
where s.division_id = 19
and s.district_cd in (72,73)
group by 1,2,3,4,5
As stated in a previous comment, the example is too long to debug, especially since the source tables are not provided.
However, as a general rule, when adding zeroes for missing dimensions, I follow these steps:
Construct the main query, this is the query with all the complexity
that pulls the data you need - just the available data, without
missing dimensions; test this query to make sure it gives correct
results, aggregated correctly by each dimension
Then use this query as a CTE in a WITH statement and to this query, you can right join all dimensions for which you want to add zero values for missing data
Be sure to double check filtering on the dimensions to ensure that you don't filter out too much in your WHERE conditions, for example, instead of filtering with WHERE on the final query, like in your example:
right join dw_dss.lu_store_finance_om s
on s.store_id = a.store_id
where s.division_id = 19
and s.district_cd in (72,73)
I might rather filter the dimension itself in a subquery:
right join (select store_id from dw_dss.lu_store_finance_om
where s.division_id = 19 and s.district_cd in (72,73)) s
on s.store_id = a.store_id
I have a query below and am trying to get all the week_id's, upc_id's and upc_dsc's pulled in even if there is no net_amt or item_qty for them.
You want to generate the rows that you want using cross join and then use left join to bring in the the data you want. In your case, you also want aggregation.
You have not explained the tables, and I find your query quite hard to follow. But the idea is:
select c.weekid, c.store_id, c.upc_id,
count(f.dayid) as num_sales,
sum(f.net_amt) as total_amt
from calendar c cross join
stores s cross join
upcs u left join
facts f
using (dayid, store_id, upc_id) -- or whatever the right conditions are
group by c.weekid, c.store_id, c.upc_id;
Obviously, you have additional filters. You would apply these filters in the where clause to the dimension tables (or use a subquery if the logic is more complicated).

LEFT JOIN help in sql

I have to make a list of customer who do not have any invoice but have paid an invoice … maybe twice.
But with my code (stated below) it contains everything from the left join. However I only need the lines highlighted with green.
How should I make a table with only the 2 highlights?
Select paymentsfrombank.invoicenumber,paymentsfrombank.customer,paymentsfrombank.value
FROM paymentsfrombank
LEFT OUTER JOIN debtors
ON debtors.value = paymentsfrombank.value
You only want to select columns from paymentsfrombank. So why do you even join?
select invoice_number, customer, value from paymentsfrombank
except
select invoice_number, customer, value from debtors;
(This requires exact matches as in your example, i.e. same amount for the invoice/customer).
There are two issues in your SQL. First, you need to join on Invoice number, not on value, as joining on value is pointless. Second, you need to only pick those payments where there are no corresponding debts, i.e. when you left-join, the table on the right has "null" in the joining column. The SQL would be something like this:
SELECT paymentsfrombank.invoicenumber,paymentsfrombank.customer,paymentsfrombank.value
FROM paymentsfrombank
LEFT OUTER JOIN debtors
ON debtors.InvoiceNumber = paymentsfrombank.InvoiceNumber
WHERE debtors.InvoiceNumber is NULL
in mysql we usually have this way to flip the relation and extract the rows that dosen't have relation.
Select paymentsfrombank.invoicenumber,paymentsfrombank.customer,paymentsfrombank.value
FROM paymentsfrombank
LEFT OUTER JOIN debtors
ON debtors.value = paymentsfrombank.value where debtors.value is null
You can use NOT EXISTS :
SELECT p.*
FROM paymentsfrombank p
WHERE NOT EXISTS (SELECT 1 FROM debtors d WHERE d.invoice_number = p.invoice_number);
However, the LEFT OUTER JOIN would also work if you add filtered with WHERE Clause to filtered out only missing customers that haven't any invoice information :
SELECT p.invoicenumber, p.customer, p.value
FROM paymentsfrombank P LEFT OUTER JOIN
debtors d
ON d.InvoiceNumber = p.InvoiceNumber
WHERE d.InvoiceNumber IS NULL;
Note : I have used table alias (p & d) that makes query to easier read & write.

Missing rows when selecting from 2 tables

Hi and sorry if that's a stupud question but I am trying to get results from two different tables and since one of them might have zero records I am not sure how to proceed. Here is the query:
SELECT aid.*, T.ItemId, T.Total, T.Stack
FROM (SELECT ItemId, Stack, count(ItemId) as Total FROM auction_house WHERE Sale = 0 GROUP BY ItemId, Stack) as T, ahbot_item_data aid
WHERE T.ItemId = aid.ItemId
AND T.Stack = aid.Stack
Basically I want to get a list of items from the aid table, and the current count of those items in the ah table. But since the count might just be zero, it might not return that row. I want the row and the Total to be 0.
Thank you in advance ^^;;
Similar to what #Twelfth was saying, you want to have a left outer join, which always outputs data from the left table even if there is no matching data in the right table.
SELECT
aid.ItemId,
count(ah.ItemId) AS "Total",
aid.Stack
FROM
ahbot_item_data aid
LEFT OUTER JOIN auction_house ah
ON (aid.ItemID = ah.ItemID AND aid.Stack = ah.Stack)
GROUP BY
aid.ItemID, aid.Stack
You are using old syntax...I'm going to switch to join syntax (newer and more accepted...same effect, easier to read). What you want is an 'outer join', which will produce nulls where no record is found. I'll arrange the tables and we'll use a left outer join
SELECT aid.*, T.ItemId, T.Total, T.Stack
FROM ahbot_item_data aid left join (SELECT ItemId, Stack, count(ItemId) as Total FROM auction_house WHERE Sale = 0 GROUP BY ItemId, Stack) as T,
on T.ItemId = aid.ItemId
AND T.Stack = aid.Stack
I'm not entirely sure on the syntax anymore...but it's also possible to use != to do this outer join in the syntax you've used (where aid.itemID != t.itemID I think?)

Select SUM from multiple tables

I keep getting the wrong sum value when I join 3 tables.
Here is a pic of the ERD of the table:
(Original here: http://dl.dropbox.com/u/18794525/AUG%207%20DUMP%20STAN.png )
Here is the query:
select SUM(gpCutBody.actualQty) as cutQty , SUM(gpSewBody.quantity) as sewQty
from jobOrder
inner join gpCutHead on gpCutHead.joNum = jobOrder.joNum
inner join gpSewHead on gpSewHead.joNum = jobOrder.joNum
inner join gpCutBody on gpCutBody.gpCutID = gpCutHead.gpCutID
inner join gpSewBody on gpSewBody.gpSewID = gpSewHead.gpSewID
If you are only interested in the quantities of cuts and sews for all orders, the simplest way to do it would be like this:
select (select SUM(gpCutBody.actualQty) from gpCutBody) as cutQty,
(select SUM(gpSewBody.quantity) from gpSewBody) as sewQty
(This assumes that cuts and sews will always have associated job orders.)
If you want to see a breakdown of cuts and sews by job order, something like this might be preferable:
select joNum, SUM(actualQty) as cutQty, SUM(quantity) as sewQty
from (select joNum, actualQty, 0 as quantity
from gpCutBody
union all
select joNum, 0 as actualQty, quantity
from gpSewBody) sc
group by joNum
Mark's approach is a good one. I want to suggest the alternative of doing the group by's before the union, simply because this can be a more general approach for summing along multiple dimensions.
Your problem is that you have two dimensions that you want to sum along, and you are getting a cross product of the values in the join.
select joNum, act.quantity as ActualQty, q.quantity as Quantity
from (select joNum, sum(actualQty) as quantity
from gpCutBody
group by joNum
) act full outer join
(select joNum, sum(quantity) as quantity
from gpSewBody
group by joNum
) q
on act.joNum = q.joNum
(I have kept Mark's assumption that doing this by joNum is the desired output.)

SQL Table A Left Join Table B And top of table B

Im working myself into an SQL frenzy, hopefully someone out there can help!
I've got 2 tables which are basically Records and Outcomes, I want to join the 2 tables together, count the number of outcomes per record (0 or more) which I've got quite easily with:
Select records.Id, (IsNull(Count(outcomes.Id),0)) as outcomes
from records
Left Join
outcomes
on records.Id = outcomes.Id
group by
records.Id
The outcomes table also has a timestamp in it, what I want to do is include the last outcome in my result set, if I add that the my query it generates a record for every combination of records to outcomes.
Can any SQL expert point me in the right direction?
Cheers,
try:
SELECT
dt.Id, dt.outcomes,MAX(o.YourTimestampColumn) AS LastOne
FROM (SELECT --basically your original query, just indented differently
records.Id, (ISNULL(COUNT(outcomes.Id),0)) AS outcomes
from records
LEFT JOIN outcomes ON records.Id = outcomes.Id
GROUP BY records.Id
) dt
INNER JOIN outcomes o ON dt.Id = o.Id
GROUP BY dt.Id, dt.outcomes