I have three tables I need to pull data for, the left table needs to always display the rows that are called out in the "where". My problem is that since there are three tables I can't get this to work. I have tried joins like crazy, it works when only doing two tables, but as soon as I get the third in there it doesn't work, it then will only display rows that are not null across all three tables. I need to be able to display the specified IDs in the first table regardless if the other two tables are completely null for the specified IDs
I have a database where I only have read access, so changing the structure on this won't work. Below is my SQL code that works as it is to get me the data I want with the exception that there is a ID that doesn't display since it has no data for the day specified.
select
[User].Id,
[User].Name,
convert(float,round(sum(SalesOrderJournalDetail.Price*SalesOrderJournalDetail.Shipped),2)) as 'Sales Yesterday',
convert(float,round(sum(SalesOrderJournalDetail.ActualCost*SalesOrderJournalDetail.Shipped),2)) as 'Cost Yesterday',
count(distinct(SalesOrderJournalDetail.SalesOrderId)) as 'Orders Yesterday',
count(SalesOrderJournalDetail.SalesOrderId) as 'Lines Yesterday',
convert(float,UserTotal.SalesMTD,2) as 'Sales MTD',
round(convert(float,UserTotal.CostMTD,2),2) as 'Cost MTD'
from
[User], UserTotal, SalesOrderJournalDetail
where
[User].Id in (' 725',' 150',' 239',' 225',' 209',' 227',' 222',' 232',' 241',' 215',' 214',' 722',' 134',' 201',' 238',' 721','M104',' 244',' 245',' 104')
and convert(varchar(10),SalesOrderJournalDetail.InvoiceDate,111) = '2012/04/19'
and [User].Id=SalesOrderJournalDetail.SalesPersonUserId
and SalesOrderJournalDetail.SalesPersonUserId=UserTotal.UserId
group by [User].Id, [User].Name, SalesOrderJournalDetail.SalesPersonUserId, UserTotal.UserId, UserTotal.SalesMTD, UserTotal.CostMTD
order by [User].Name
To help explain the structure, the [User] table displays the user's ID number and Name, the SalesOrderJournalDetail table displays the current day's sales, and the UserTotal table displays the monthly sales data (via some calculations).
I need to display the day's sales and monthly sales from the latter two tables, and need to pull the user's name and ID from the first.
All three table's unique data are [User].Id, SalesJournalDetail.SalesPersonUserId, and UserTotal.UserId
Any ideas how I can get this to show all the ID's shown in the where cluase regardless if there are no day or monthly sales for that user?
Oh and this is using Microsoft SQL
Created tables with your structure. Very minor column name changes are there. Please change accordingly. ActualCost is ActualPrice in my table.
Following will be the query
SELECT
ISNULL(SalesJournalUserId,TotalSalesUserId) AS UserId,
ISNULL(SalesJournalUserName,TotalSalesUserName) AS UserName,
[Orders Yesterday],
[Lines Yesterday],
[Sales Yesterday],
[Cost Yesterday],
[Sales MTD],
[Cost MTD] FROM
(
(
SELECT
SalesUser.Id as SalesJournalUserId,
SalesUser.Name as SalesJournalUserName,
[Orders Yesterday],
[Lines Yesterday],
[Sales Yesterday],
[Cost Yesterday]
FROM
[SalesUser]
LEFT JOIN
(
select
[User].Id,
[User].Name,
Count(distinct(SalesOrderJournalDetail.ID)) as 'Orders Yesterday',
Count((SalesOrderJournalDetail.ID)) as 'Lines Yesterday',
convert(float,round(sum(SalesOrderJournalDetail.Price*SalesOrderJournalDetail.Shipped),2)) as 'Sales Yesterday',
convert(float,round(sum(SalesOrderJournalDetail.ActualPrice*SalesOrderJournalDetail.Shipped),2)) as 'Cost Yesterday'
from
[SalesUser] as [User]
LEFT JOIN SalesOrderJournalDetail
on [User].Id = SalesOrderJournalDetail.SalesPersonUserId
where
--[User].Id =1 and
convert(varchar(10),SalesOrderJournalDetail.InvoiceDate,111) = '2012/04/19'
group by [User].Id,[user].Name
) SOJD
ON SalesUser.Id = SOJD.ID
) SOJDALLUSERS
INNER JOIN
(
SELECT
SalesUser.Id as TotalSalesUserId,
SalesUser.Name as TotalSalesUserName,
[Sales MTD],
[Cost MTD]
FROM
[SalesUser]
LEFT JOIN
(
select
[User].Id,
[User].Name,
convert(float,sum(UserTotal.SalesMTD),2) as 'Sales MTD',
round(convert(float,sum(UserTotal.CostMTD),2),2) as 'Cost MTD'
from
[SalesUser] as [User]
LEFT JOIN UserTotal
on [User].Id = UserTotal.UserId
--where
--[User].Id =1
group by [User].Id,[User].name
) AS SOUT
ON SalesUser.Id = SOUT.ID
) SOUTALLUSERS
ON SOJDALLUsers.SalesJournalUserId = SOUTALLUSERS.TotalSalesUserId
)
How it works
Subquery SOJDALLUSERS: Joins SalesUser table with your SalesOrderJournalTable. Fetches data for every user
Subquery SOUT : Joins SalesUser table with UserTotal table. fetches data for every user. Your SalesMTD and CostMTD should be a "SUM" for every user if i am not wrong. You have missed it.
The above two results are inner joined to get the details for every user. Since the above subquery brings data for every user in sales table, an inner join for the above two subqueries will guarantee data for all users with appropriate null values whenever data is missing.
I have created the tables and checked following scenarios
1. data in both journal and salestotal table for a user
2. data in journal table but not in salestotal table for a user
3. data in salestotal table but not in journal table for a user.
IT WORKS.. ENJOY
Table schema for your reference
Mark as answer if it gives you some direction into your problem. It was a nice challenge doing this query..
Related
I am experienced at VBA but new to SQL.
I am developing a test sheet program in MS Access for the plant that I work at. This test sheet program will be used across 3 product lines.
When an order is created, it can contain up to all 3 products. The products are unique enough that I cannot put them all into their own table. So I have broken the test sheets up into 3 tables, each table representing its respective product test sheet. Please see the image below for my relationship setup.
What I am trying to do:
I am trying to design a query that will be my master list (outputting to a continuous form). The master list will show all orders, and also show how many units have been tested in each order. See below for my desired output.
My Issue:
It is not properly counting the number of related records. See the linked photo.
I know my key field is Order Number but I am searching by Job name. Originally my key field was job name but then switched it to order number.
thank you for your time, I am happy to provide more information if needed.
Consider joining three aggregate saved queries:
SELECT OrderNumber
, COUNT(*) AS CountofCassetteTests
FROM TblCassetteTestSheet
GROUP BY OrderNumber
SELECT OrderNumber
, COUNT(*) AS CountofSentinelTests
FROM TblSentinelTestSheet
GROUP BY OrderNumber
SELECT OrderNumber
, COUNT(*) AS CountofHUVTests
FROM TblHUVTestSheet
GROUP BY OrderNumber
Then join to TblJobName in your final query (parentheses are required):
SELECT j.OrderNumber, j.JobName
, c.CountofCassetteTests AS [# Of Cassettes Tested]
, s.CountofSentinelTests AS [# Of Sentinels Tested]
, h.CountofHUVTests AS [# Of HUV Tested]
, j.JobEndDate, j.SPONumber
FROM ((TblJobName j
LEFT JOIN QryCassetteTestSheet c
ON j.OrderNumber = c.OrderNumber)
LEFT JOIN QrySentinelTestSheet s
ON j.OrderNumber = s.OrderNumber)
LEFT JOIN QryHUVTestSheet h
ON j.OrderNumber = h.OrderNumber
Conceivably you can run all in one query using subqueries (and maybe one day even Common Table Expressions, CTEs, if the MS Access team ever enhances its older SQL dialect):
SELECT j.OrderNumber, j.JobName
, c.CountofCassetteTests AS [# Of Cassettes Tested]
, s.CountofSentinelTests AS [# Of Sentinels Tested]
, h.CountofHUVTests AS [# Of HUV Tested]
, j.JobEndDate, j.SPONumber
FROM ((TblJobName j
LEFT JOIN
(SELECT OrderNumber, COUNT(*) AS CountofCassetteTests
FROM TblCassetteTestSheet
GROUP BY OrderNumber) c
ON j.OrderNumber = c.OrderNumber)
LEFT JOIN
(SELECT OrderNumber, COUNT(*) AS CountofSentinelTests
FROM TblSentinelTestSheet
GROUP BY OrderNumber) s
ON j.OrderNumber = s.OrderNumber)
LEFT JOIN
(SELECT OrderNumber, COUNT(*) AS CountofHUVTests
FROM TblHUVTestSheet
GROUP BY OrderNumber) h
ON j.OrderNumber = h.OrderNumber
I have created 3 queries. Each query counts the number of tests for that product that are associated with an order number. Below you will see my code for
QryCountofTestedHUV
SELECT TblJobName.OrderNumber, TblJobName.JobName
(
SELECT
Count(*)
FROM
TblHUVTestSheet
Where TblHUVTestSheet.OrderNumber=TblJobName.OrderNumber
) AS CountofHUVTests
FROM TblJobName LEFT JOIN TblHUVTestSheet ON TblJobName.OrderNumber = TblHUVTestSheet.OrderNumber
GROUP BY TblJobName.OrderNumber, TblJobName.JobName;
From there I have gone into the relationships view, and linked QryCountofTestedHUV.OrderNumber to TblJobName.OrderNumber. Now I can add CountofHUVTests from query QryCountofTestedHUV as a field to my query, QryAllJobs! QryAllJobs is my master list I showed earlier.
I have repeated this 3 times for all 3 product lines and it works!
below are two tables customer information and second customer with their loan and repayment I want to join these two tables and retrieve the expected result in the picture, please note that in the second table one customer can have more than one loan and he/she can repay it in several installments that in the second table that it saved in many rows, I am expecting to join the two tables and retrieve clients who are still owed from the company.
I found the expected result as a good solution for this purpose but could not retrieve the expected result.
and if you have a good solution for my purpose rather than expected result please share.
example:-
I tried below query but it does not work, because the client id number 1 disbursed three times loan when it shows the tree times purpose it shows that total of the loan three times too
SELECT DISTINCT
CUSTOMER_AIB_INFO_TABLE.ID,
CUSTOMER_AIB_INFO_TABLE.NAME,
(
SELECT SUM (CUSTOMER_AIB_LOAN_TABLE.LOAN) AS "Total Loan"
FROM CUSTOMER_AIB_LOAN_TABLE
WHERE CUSTOMER_AIB_INFO_TABLE.ID = CUSTOMER_AIB_LOAN_TABLE.FK_ID
) AS "Loan",
(
SELECT SUM (CUSTOMER_AIB_LOAN_TABLE.REPAYMENT) FROM CUSTOMER_AIB_LOAN_TABLE
WHERE CUSTOMER_AIB_INFO_TABLE.ID = CUSTOMER_AIB_LOAN_TABLE.FK_ID
) AS Repayment ,
CUSTOMER_AIB_LOAN_TABLE.PURPOSE
FROM CUSTOMER_AIB_INFO_TABLE
INNER JOIN CUSTOMER_AIB_LOAN_TABLE
ON CUSTOMER_AIB_INFO_TABLE.ID = CUSTOMER_AIB_LOAN_TABLE.FK_ID
Instead of Subquery you could use a inner join on select table group by id
SELECT DISTINCT
CUSTOMER_AIB_INFO_TABLE.ID,
CUSTOMER_AIB_INFO_TABLE.NAME,
T.Total_Loan AS "Loan",
T.Total_Rep AS Repayment,
CUSTOMER_AIB_LOAN_TABLE.PURPOSE
FROM CUSTOMER_AIB_INFO_TABLE
INNER JOIN (
SELECT CUSTOMER_AIB_LOAN_TABLE.FK_ID as FK_ID,
SUM (CUSTOMER_AIB_LOAN_TABLE.LOAN) AS Total_Loan
, SUM (CUSTOMER_AIB_LOAN_TABLE.REPAYMENT) AS Total_Rep
FROM CUSTOMER_AIB_LOAN_TABLE
GROUP BY CUSTOMER_AIB_LOAN_TABLE.ID
) T on t.FK_ID = CUSTOMER_AIB_INFO_TABLE.ID
I'm trying to join 2 tables to get an output report. The tables involved are the stock and dailysales table.
Stock and Dailysales tables:
Desired output format:
I am trying to join 2 tables by using the below query
Select item,article,sold,stockonhand
from stock S
left join dailysales as D on S.item=D.item
group by item
I want the output to include all rows from the stock table. Like there is stock, but not sold, also to be included in the report. Currently my report is does not show, (stocked but not sold).
Hope you can understand my context or point me to a tutorial which I could read up. I tried to search for few days and couldn't find an exact question to mine.
Not tested -
select item,article,sum(sold),sum(stockonhand)-sum(sold) from (
select a.item,a.article,a.stockonhand,case when b.sold is null then 0 else b.sold end as sold
from stock a left join dailysales b on (a.item = b.item))
group by item,article;
It's basically does the left join and put 0 on the null column(for sum after)
and then summing up the results grouping by all the columns in the select(that what was wrong with your query)
Simply LEFT JOIN the two tables (to get the flute too), do a GROUP BY, and SUM the sold:
select s.item, s.article, coalesce(SUM(d.sold),0) as "qty sold", s.stockonhand
from stock S
left join dailysales as D on S.item=D.item
group by s.item, s.article, s.stockonhand
The coalesce is there to replace NULL with 0, for items not sold. (Thanks sagi!)
General GROUP BY tip: If a GROUP BY clause is specified, each column reference in the SELECT list must either identify a grouping column or be the argument of a set function.
Also, you can remove the article column from the dailysales table. That data is already stored in the stock table. Never store same data twice! (Normalization!) Risk for data inconsistency if you keep that column.
You can sum the item in a separated table, it would be clearer than GROUP BY 2 tables
SELECT
s.item,
s.article,
ISNULL(ds.sold, 0) AS qtysold,
s.stockonhand
FROM
stock s OUTER APPLY
(SELECT SUM(sold) AS sold FROM dailysales WHERE item = s.item GROUP BY item) ds
So basically what I'm trying to do is generate a report for our stores. We have an incident report website where the employees can report an incident that takes place at any of our stores. So in the general report I'm trying to generate, I want to show the details for each store we have (Five stores). This would include the name of the store, number of incidents, oldest incident date, newest incident date, and then the most recurring type of incident at each store.
SELECT Store.Name AS [Store Name], COUNT(*) AS [No. Of Incidents], Min(CAST(DateNotified AS date)) AS [Oldest Incident], Max(CAST(DateNotified AS date)) AS [Latest Incident],
( SELECT TOP 1 IncidentType.Details
FROM IncidentDetails
INNER JOIN Store ON IncidentDetails.StoreID = Store.StoreID
INNER JOIN IncidentType On IncidentDetails.IncidentTypeID = IncidentType.IncidentTypeID
Group By IncidentType.Details, IncidentDetails.StoreID
Order By COUNT(IncidentType.Details) DESC) AS [Most Freqeuent Incident]
FROM IncidentDetails
INNER JOIN Store ON IncidentDetails.StoreID = Store.StoreID
INNER JOIN IncidentType On IncidentDetails.IncidentTypeID = IncidentType.IncidentTypeID
GROUP BY Store.Name
Just to make it clear, the IncidentDetails table stores all the details about the incident including which store it occured at, what the type of incident was, time/date, etc.
What this does though is it gives me 5 rows for each store, but the [Most Frequent Incident] value is the same for every row. Basically, it gets the most frequent incident value for the whole table, regardless of which store it came from, and then displays that for each store, even though different stores have different values for the column.
I've been trying to solve this for a while now but haven't been able to :-(
You have too many joins and no correlation clause.
There are several ways to approach this problem. You have already started with an aggregation in the outer query and then a nested subquery. So, this continues that approach. I think this does what you want:
SELECT s.Name AS [Store Name], COUNT(*) AS [No. Of Incidents],
Min(CAST(DateNotified AS date)) AS [Oldest Incident],
Max(CAST(DateNotified AS date)) AS [Latest Incident],
(SELECT TOP 1 it.Details
FROM IncidentDetails id2 INNER JOIN
IncidentType it2
On id2.IncidentTypeID = it2.IncidentTypeID
WHERE id2.StoreId = s.StoreId
Group By it.Details
Order By COUNT(*) DESC
) AS [Most Freqeuent Incident]
FROM IncidentDetails id INNER JOIN
Store s
ON id.StoreID = s.StoreID
GROUP BY s.Name, s.StoreId;
Notes:
Removed the IncidentType table from the outer joins. This doesn't seem needed (although it could be used for filtering).
Added s.StoredId to the group by clause. This is needed for the correlation in the subquery.
Added a where clause so the subquery is only processed once for each store in the outer query.
Removed the join to Store in the subquery. It seems unnecessary, if the queries can be correlated on StoreId.
Changed the group by in the subquery to use Details. That is the value being selected.
Added table aliases, which make queries easier to write and to read.
I have three tables TeamTerritoryMapping, UpdQuotaTbl and tblInvoiceFile
When I join the first two tables I am getting the correct result
select
TTM.Team, Sum(Upd.Quota) as Quota
from
TeamTerritoryMapping TTM
inner join
UpdQuotaTbl upd on upd.ITM = TTm.Territory
where
upd.Month = 'july'
group by
TTM.Team
but when I join the third table for another column revenue from tblinvoicefile, some of the rows are getting duplicated and the end result is becoming higher. Below is the query which I am using to join 3 tables
select
TTM.Team,
Sum(upd.Quota) as quota,
sum(inv.[End MS Sales Revenue]) as Revenue
from
UpdQuotaTbl Upd
inner join
TeamTerritoryMapping TTM on TTM.Territory = upd.ITM
inner join
tblInvoiceFile inv on inv.[Inv Territory] = TTM.Territory
where
upd.Month = 'july'
and inv.[End Fiscal Month] = 'July, 2013'
So how can I eradicate the duplicate values in third table, I am getting the correct value when I join two tables ie TeamTerritoryMapping,UpdQuotaTbl and also tables TeamTerritoryMapping.
It looks like tblInvoiceFile has multiple entires for [Invenio Territory] which is causing this issue. If your intention is to bring in and sum all the [End MS Sales Revenue] for that table you can try something like this
SELECT TTM.Team,Sum(upd.Quota) as quota,sum(inv.[End MS Sales Revenue]) as Revenue
FROM UpdQuotaTbl Upd
INNER JOIN TeamTerritoryMapping TTM ON TTM.Territory = upd.ITM
INNER JOIN
(SELECT [Invenio Territory], SUM([End MS Sales Revenue]) AS [End MS Sales Revenue]
FROM tblInvoiceFile
WHERE [End Fiscal Month] = 'July, 2013'
GROUP BY [Invenio Territory]) AS inv
ON inv.[Invenio Territory] = TTM.Territory
WHERE upd.Month = 'july'
My initial response would be : The reason you're getting some results multiple times is because the ON used to join tblInvoiceFile is not 'unique' enough. If you look at the primary key (or a unique?) of said table you'll probably notice that it involves more than just the Inv Territory field.
To solve it you can do two different things.
Expand the ON clause to include more fields that make the connection unique
Keep the query as it is now but aggregate the results so the invoice information gets SUMmed
The problem is, it seems like you're already SUM()-ing the information (although as noted by Win, you're missing the GROUP BY), so I'm not quite sure why this would not work.
UPDATE: Only now realise that your problem is not doubled records, but doubled values in the first SUM(). Best way to solve this is by PRE-aggregating the values as shown by Abhi.