Simplify SQL query with multiple Sub-Selects - sql

Goal
I would like to simplify the following sql query in term of visual length (decrease amount nested sub-selects) and/or performance and/or readability. This query is dedicated for MS Access, that's why there are parenthesis around INNER JOIN.
Explanation
To not lose global view all table relations are shortened after ON clauses.
Table S1 and S2 is the same table S. To work, the query (MS Access to be precise) needed to separate names of S in different sub-selects.
Level 1 query (T1) calculates: qty of defects, qty of production and defect rate in PPM for all production areas and subareas in specific period of time.
Level 2 query (T2) calculates sum of defect rates from in T1 per area and adds some additional information like specific one main user from many attached to areas, area name itself and target taken for specific year and month.
Level 3 query takes all from level 2 and adds some comment defined for specific year and week and also filter all the list down to areas where sum of defect rates exceeds target.
This query works as expected and all the columns in the result table show properlly calculated values and fields.
Is it possible to simplify this query?
Note
I added sql-server tag to reach more pro-users. Sorry if it doesn't fit.
Query
SELECT s1id, s2name, user, target, ratio, C.msg AS msg
FROM
(SELECT s1id, S2.nam AS s2name, (U.lastname & ' ' & U.firstname) AS user, T.m1 AS target, SUM(ratio1) as ratio
FROM ((((
(SELECT S1.id AS s1id, WG.id AS wgid, SUM(IIF(D.ok=False,F.qty,0)) AS nok, SUM(F.qty) AS production, IIF(production > 0, CLNG(nok/production * 1000000), 0) AS ratio1
FROM (((F
INNER JOIN D ON D.x = F.x)
INNER JOIN W ON W.x = D.x)
INNER JOIN WG ON WG.x = W.x)
INNER JOIN S1 ON S1.x = WG.x
WHERE F.entrydate BETWEEN #2017-01-23# And #2017-01-29#
GROUP BY S1.id, WG.id) AS T1
INNER JOIN S2 ON S2.x = T1.x)
INNER JOIN UPS ON UPS.x = S2.x)
INNER JOIN UP ON UP.x = UPS.x)
INNER JOIN U ON U.x = UP.x)
INNER JOIN T ON T.x = S2.x
WHERE UPS.main = true AND UP.positionid = 3 AND T.y = 2017
GROUP BY sectorid, S2.nam, U.lastname, U.firstname, T.m1) AS T2
INNER JOIN C ON C.x = T2.x
WHERE C.yearnum = 2017 AND C.weeknum = 4 AND ratio > target

Related

How to Display Two Query Side by Side using SQL

I have the following 2 queries that are almost identical except the second query contains a table join, where clause and has less FAXDEPTs(the commented out portion is included in Query 2 just shared the one query to make easier to read).
I want to join the two queries by FAXDEPT and have the results look something like this,
FAXDEPT| TOTAL DOCUMENTS(Query1)|TOTAL PAGES (Query1)|TOTAL DOCUMENTS(Query2)|TOTAL PAGES (Query2)
Query 1 contains more FAXDEPTs than Query2. Is there a way I can display "0"s for Query 2 TOTAL PAGES and TOTAL DOCS
I'm assumed I would do some sort of FUll OUTER JOIN but can't seem to get it to work. Not sure if using alias is part of my issue or not. I appreciate all the help in advance!
select sq.faxdept 'Fax Department', count(sq.docid)'Total Documents', sum(sq.pages)'Total Pages'
from
(
select idp.id as docid, (MAX(idp.pagenum)+1) as pages, ki178.keyvaluechar as faxdept
from DOCDATA dd
left join FAXDEPT ki178 on id.id = ki178.id
left join IMPORTSOURCE ki228 on id.id = ki228.id
left join BATCHINFO kgd105 on dd.id = kgd105.id
left join PAGEDATA idp on id.id = idp.id
--left join QUEUE ilc on id.id = ilc.id
where
id.datestored > '10/07/2021' and id.status = 0
--and ilc.num = 252
and (kgd105.kg128 like 'DISC DIP%SJIN%' or ki228.keyvaluechar like 'SJIN' )
group by idp.id, ki178.keyvaluechar
)
as sq
group by sq.faxdept

SQL - faster to filter by large table or small table

I have the below query which takes a while to run, since ir_sales_summary is ~ 2 billion rows:
select c.ChainIdentifier, s.SupplierIdentifier, s.SupplierName, we.Weekend,
sum(sales_units_cy) as TY_unitSales, sum(sales_cost_cy) as TY_costDollars, sum(sales_units_ret_cy) as TY_retailDollars,
sum(sales_units_ly) as LY_unitSales, sum(sales_cost_ly) as LY_costDollars, sum(sales_units_ret_ly) as LY_retailDollars
from ir_sales_summary i
left join Chains c
on c.ChainID = i.ChainID
inner join Suppliers s
on s.SupplierID = i.SupplierID
inner join tmpWeekend we
on we.SaleDate = i.saledate
where year(i.saledate) = '2017'
group by c.ChainIdentifier, s.SupplierIdentifier, s.SupplierName, we.Weekend
(Worth noting, it takes roughly 3 hours to run since it is using a view that brings in data from a legacy service)
I'm thinking there's a way to speed up the filtering, since I just need the data from 2017. Should I be filtering from the big table (i) or be filtering from the much smaller weekending table (which gives us just the week ending dates)?
Try this. This might help, joining a static table as first table in query onto a fact/dynamic table will impact query performance i believe.
SELECT c.ChainIdentifier
,s.SupplierIdentifier
,s.SupplierName
,i.Weekend
,sum(sales_units_cy) AS TY_unitSales
,sum(sales_cost_cy) AS TY_costDollars
,sum(sales_units_ret_cy) AS TY_retailDollars
,sum(sales_units_ly) AS LY_unitSales
,sum(sales_cost_ly) AS LY_costDollars
,sum(sales_units_ret_ly) AS LY_retailDollars
FROM Suppliers s
INNER JOIN (
SELECT we
,weeekend
,supplierid
,chainid
,sales_units_cy
,sales_cost_cy
,sales_units_ret_cy
,sales_units_ly
,sales_cost_ly
,sales_units_ret_ly
FROM ir_sales_summary i
INNER JOIN tmpWeekend we
ON we.SaleDate = i.saledate
WHERE year(i.saledate) = '2017'
) i
ON s.SupplierID = i.SupplierID
INNER JOIN Chains c
ON c.ChainID = i.ChainID
GROUP BY c.ChainIdentifier
,s.SupplierIdentifier
,s.SupplierName
,i.Weekend

Using summed field in query twice with IIF statement - have I missed some syntax somewhere?

Having a bit of a problem with my code and can't figure out where I'm going wrong.
Essentially this query will return all employees for a given employer for a given year, along with the amount of their allowances, tax withheld, and gross payments they've received, and their Reportable Employer Superannuation Contributions (RESC).
RESC is any amounts (tblSuperPayments.PaymentAmount) paid over and above the superannuation guarantee, which is gross payments (sum of tblPayment.GrossPayment) * super rate (tblSuperRate.SuperRate). Otherwise, RESC is 0.
The data that I currently have in my tables is as follows
SUM(tblPayment.GrossPayment) = 1730
SUM(tblEmployee.TaxPayable) = 80
SUM(tblSuperPayments.PaymentAmount) = 500
tblSuperRate.SuperRate = 9.5%
Therefore my query should be returning an amount of RESC of 500-(1730*9.5%)= 335.65.
However, my query is currently returning $835.65 - meaning that (1730*9.5%) is returning -335.65.
I can't figure out where my logic is going wrong - it's probably something simple but I can't see it. I suspect that it might be summing tblPayment.GrossPayment twice (edited on request)
SELECT
tblEmployee.EmployeeID AS Id
SUM(tblPayment.Allowances) AS TotAllow,
SUM(tblPayment.TaxPayable) AS TotTax,
SUM(tblPayment.GrossPayment) AS TotGross,
(IIF
((SUM(tblSuperPayments.PaymentAmount)) <= (SUM(tblPayment.GrossPayment)*tblSuperRate.SuperRate),
0,
(SUM(tblSuperPayments.PaymentAmount) - (SUM(tblPayment.GrossPayment)*tblSuperRate.SuperRate))
)) As TotRESC
FROM
((tblEmployee
LEFT JOIN tblPayment // any reason for using left join over inner join
ON tblEmployee.EmployeeID = tblPayment.fk_EmployeeID)
LEFT JOIN tblSuperPayments // any reason for using left join over inner join
ON tblEmployee.EmployeeID = tblSuperPayments.fk_EmployeeID)
LEFT JOIN tblSuperRate // any reason for using left join over inner join
ON (tblPayment.PaymentDate <= tblSuperRate.TaxYearEnd) // these two conditions might be returning
AND (tblPayment.PaymentDate >= tblSuperRate.TaxYearStart) //two SuperRate rows because of using equals in both
WHERE
tblEmployee.fk_EmployerID = 1
GROUP BY
tblEmployee.EmployeeID,
tblSuperRate.SuperRate;
Looking at your query I recommend you to just group by primary key (EmployeeID) of tblEmployee and the use the result as a sub query and do a join later tham using many columns of tblEmployeein group by which might cause duplicate rows. I rewrote the query as I have mentioned above and added comments at places which might cause the error.
SELECT
tblEmployee.TFN,
tblEmployee.FirstName,
tblEmployee.MiddleName,
tblEmployee.LastName,
tblEmployee.DOB,
tblEmployee.MailingAddress,
tblEmployee.AddressLine2,
tblEmployee.City,
tblEmployee.fk_StateProvinceID,
tblEmployee.PostalCode,
temp.TotAllow,
temp.TotTax,
temp.TotGross,
temp.TotRESC
FROM
(SELECT
tblEmployee.EmployeeID AS Id
SUM(tblPayment.Allowances) AS TotAllow,
SUM(tblPayment.TaxPayable) AS TotTax,
SUM(tblPayment.GrossPayment) AS TotGross,
(IIF
((SUM(tblSuperPayments.PaymentAmount)) <= (SUM(tblPayment.GrossPayment)*tblSuperRate.SuperRate),
0,
(SUM(tblSuperPayments.PaymentAmount) - (SUM(tblPayment.GrossPayment)*tblSuperRate.SuperRate))
)) As TotRESC
FROM
((tblEmployee
LEFT JOIN tblPayment // any reason for using left join over inner join
ON tblEmployee.EmployeeID = tblPayment.fk_EmployeeID)
LEFT JOIN tblSuperPayments // any reason for using left join over inner join
ON tblEmployee.EmployeeID = tblSuperPayments.fk_EmployeeID)
LEFT JOIN tblSuperRate // any reason for using left join over inner join
ON (tblPayment.PaymentDate <= tblSuperRate.TaxYearEnd) // these two conditions might be returning
AND (tblPayment.PaymentDate >= tblSuperRate.TaxYearStart) //two SuperRate rows because of using equals in both
WHERE
tblEmployee.fk_EmployerID = 1
GROUP BY
tblEmployee.EmployeeID,
tblSuperRate.SuperRate) temp // Does a single employee have more than one superrate why grouping by it?
JOIN tblEmployee ON tblEmployee.EmployeeID=temp.Id;

Joining SQL tables to compare revenue vs expense

Let me say first that I'm new to SQL, and learning much every day. With that said, here is my problem. I have a view that is already created (It shows revenue generated on equipment), but I need one more table added to it (Expenses against the equipment). When I try to add an inner join table, it create a bunch of duplicate views. Here is my original view (For the revenue portion of it):
SELECT
<removed, there are about 25 of them>
FROM
dbo.LRCON WITH (nolock)
INNER JOIN dbo.LRCONVIN WITH (nolock) ON dbo.LRCONVIN.ConId = dbo.LRCON.ConId
INNER JOIN dbo.LRBILCON WITH (nolock) ON dbo.LRBILCON.ConId = dbo.LRCONVIN.ConId AND dbo.LRBILCON.UntId = dbo.LRCONVIN.UntId
INNER JOIN dbo.LRBILITM WITH (nolock) ON dbo.LRBILITM.ParentItmId = dbo.LRBILCON.ItmId
INNER JOIN dbo.LRBIL WITH (nolock) ON dbo.LRBIL.BilId = dbo.LRBILCON.BilId
INNER JOIN dbo.LRCONTYP WITH (nolock) ON dbo.LRCONTYP.ConTypId = dbo.LRCON.ConTypId
INNER JOIN dbo.COLOOKUP AS C1 WITH (nolock) ON C1.Id = dbo.LRBILITM.ItmTyp
INNER JOIN dbo.COLOOKUP AS C2 WITH (nolock) ON C2.Id = dbo.LRCONTYP.ConTyp
INNER JOIN dbo.VHVIN WITH (nolock) ON dbo.VHVIN.UntId = dbo.LRCONVIN.UntId
WHERE
(dbo.LRBIL.Status = 647) AND (dbo.LRBILITM.ItmTyp <> 274)
I then try to add another join:
INNER JOIN dbo.SVSLS WITH (nolock) on dbo.SVSLS.UntId = dbo.LRCONVIN.UntId
with the select statement:
ROUND(dbo.SVSLS.AmtSubtotal + dbo.SVSLS.AmtSupplies + dbo.SVSLS.AmtDiagnostic + dbo.SVSLS.AmtTax1 + dbo.SVSLS.AmtTax2, 2) AS SvcAmtSale
... but it produces many, many rows of duplicates because it adds the detail of each expense to each row of my original table.
Original table:
https://dl.dropboxusercontent.com/u/81145403/orginal_table.jpg
After I add my new join/select:
https://dl.dropboxusercontent.com/u/81145403/failed_table.jpg
How do I fix this? At the end of the day, I just want to compare my revenue vs expenses on equipment over a date range. I really don't care to have the individual detail of the expenses, just a grand total is fine with me.
Is the SvcSaleAmt the revenue that you are interested in? And are the multiple detail rows separate entries on the same item? If you do not necessarily care about the individual details, you can GROUP the items together. In order to do this, you will need to get rid of the SlsId from your SELECT list, and add
GROUP BY CusId, CusName, BillId, ConId, Prd, ConTypId, ....., AmtCos, AmtGpm
Using all of the columns you have in your SELECT statement. Replace the ROUND() AS SvcSaleAmt with:
ROUND(SUM(dbo.SVSLS.AmtSubtotal + dbo.SVSLS.AmtSupplies + dbo.SVSLS.AmtDiagnostic + dbo.SVSLS.AmtTax1 + dbo.SVSLS.AmtTax2), 2) AS SvcSaleAmt

sql query for report produce wrong result

I have this problem regarding sql which i will be using in a webservice if I can get this right. What I wanted to do is create a summary report of a transaction. The transaction have header and lines. In a transaction, we are going to input a many planks.
After the inputing, I would like to produce a report that would add all the plank that belongs to a category, then multiply all the planks by the price of that supplier so that I can have the total amount. Here is a pic:
below is my sql which produce wrong output:
select
t1.transaction_num,
wo1.wood_classification_desc,
wo2.wood_specie_desc,
sum(t2.board_foot) as total_board_foot,
su1.price,
sum(t2.board_foot*su1.price) as total_amount
from
"transaction_hdr" t1
left join "transaction_lne" t2 on (t1.transaction_id = t2.transaction_id)
left join "supplier" su2 on (t1.supplier_id = su2.supplier_id)
left join "supplier_price" su1 on (t2.price = su1.price)
left join "wood_classification" wo1 on (t2.wood_classification_id = wo1.wood_classification_id)
left join "wood_specie" wo2 on (wo1.wood_specie_id = wo2.wood_specie_id)
group by
t1.transaction_num,wo1.wood_classification_desc,su1.price,su2.supplier_name,wo2.wood_specie_desc
order by transaction_num,wo2.wood_specie_desc
Evrytime I run that sql, it produces somthing like this:
the transaction that i test only have five planks. 4 planks under Mahogany 6" wider - 7ft. up and 1 Mahogany 5" wider - 7ft. up.
I would guess, that in one of the left joins you have more than one record, which means it give you wrong sum (group by will affect the set after the left join).
Just run the sql without the grouping and check what you get.
So it's probably not the multiplication that causes the problem, it's the sum.
Do you have more than one record in supplier_price with price = 13.33 ? That would be my guess, as all the other joins appear to be on primary keys..
EDIT:
Your problem is that you're joining to supplier_price on the price field, which is not a valid key. Given that your output doesn't take anything from the supplier_price table, I'd be inclined to remove it from the query altogether as below:
select
t1.transaction_num,
wo1.wood_classification_desc,
wo2.wood_specie_desc,
sum(t2.board_foot) as total_board_foot,
t2.price,
sum(t2.board_foot*t2.price) as total_amount
from
"transaction_hdr" t1
left join "transaction_lne" t2 on (t1.transaction_id = t2.transaction_id)
left join "supplier" su2 on (t1.supplier_id = su2.supplier_id)
left join "wood_classification" wo1 on (t2.wood_classification_id = wo1.wood_classification_id)
left join "wood_specie" wo2 on (wo1.wood_specie_id = wo2.wood_specie_id)
group by
t1.transaction_num,wo1.wood_classification_desc,t2.price,su2.supplier_name,wo2.wood_specie_desc
order by transaction_num,wo2.wood_specie_desc
This may solve the issue. But it would help if you provided the relationships between the tables (and the tables' primary keys):
select
t1.transaction_num,
wo1.wood_classification_desc,
wo2.wood_specie_desc,
sum(t2.board_foot)
as total_board_foot,
( SELECT DISTINCT su1.price
FROM "supplier_price" su1
WHERE t2.price = su1.price
) AS price,
sum(t2.board_foot) *
( SELECT DISTINCT su1.price
FROM "supplier_price" su1
WHERE t2.price = su1.price
)
as total_amount
from
"transaction_hdr" t1
left join "transaction_lne" t2
on (t1.transaction_id = t2.transaction_id)
left join "supplier" su2
on (t1.supplier_id = su2.supplier_id)
left join "wood_classification" wo1
on (t2.wood_classification_id = wo1.wood_classification_id)
left join "wood_specie" wo2
on (wo1.wood_specie_id = wo2.wood_specie_id)
group by
t1.transaction_num
, wo1.wood_classification_desc
, su2.supplier_name
, wo2.wood_specie_desc
order by transaction_num
, wo2.wood_specie_desc