Append SQL columns based on different JOINs - sql

My problem is I have a table where I want to return a column from an SQL database as two different columns based on different JOIN conditions.
My two select statements:
My first statement returns the check numbers and amounts for all of our checks that have gone through the process of being deposited -> and then ipaced (just a term).
SELECT COURTESY_CHECK.CHECK_NUMBER,
COURTESY_CHECK.CHECK_AMOUNT,
CHECK_DEPOSIT.ID AS DEPOSIT_ID
FROM COURTESY_CHECK
INNER JOIN CHECK_DEPOSIT ON CHECK_DEPOSIT.COURTESY_CHECK_ID = COURTESY_CHECK.ID
INNER JOIN DEPOSIT ON CHECK_DEPOSIT_ID = DEPOSIT.ID
INNER JOIN IPAC ON DEPOSIT.ID = IPAC.DEPOSIT_ID
My second statement returns the check numbers and amounts of the checks that have just been deposited.
SELECT COURTESY_CHECK.CHECK_NUMBER,
COURTESY_CHECK.CHECK_AMOUNT,
CHECK_DEPOSIT.ID AS DEPOSIT_ID
FROM COURTESY_CHECK
INNER JOIN CHECK_DEPOSIT ON CHECK_DEPOSIT.COURTESY_CHECK_ID = COURTESY_CHECK.ID
I would like to have a table like
IPAC/DEPOSITED AMOUNT DEPOSITED AMOUNT CHECK_NUMBER
--------------------- ---------------- ------------
$4.00 123456
$5.00 654321
I'm using BIRT to compile reports and it really only allows you to chart data based on single data sets (which is a single query) AFAIK. I'd like to chart the total "IPAC/Deposited" amount versus the "Deposited" amount.

You're really close. Wouldn't a UNION query do the trick? Something like this:
SELECT COURTESY_CHECK.CHECK_NUMBER,
COURTESY_CHECK.CHECK_AMOUNT AS [IPAC AMOUNT],
null AS [DEPOSITED AMOUNT],
CHECK_DEPOSIT.ID AS DEPOSIT_ID
FROM COURTESY_CHECK
INNER JOIN CHECK_DEPOSIT ON CHECK_DEPOSIT.COURTESY_CHECK_ID = COURTESY_CHECK.ID
INNER JOIN DEPOSIT ON CHECK_DEPOSIT_ID = DEPOSIT.ID
INNER JOIN IPAC ON DEPOSIT.ID = IPAC.DEPOSIT_ID
UNION
SELECT COURTESY_CHECK.CHECK_NUMBER, null AS [IPAC AMOUNT],
COURTESY_CHECK.CHECK_AMOUNT AS [DEPOSITED AMOUNT],
CHECK_DEPOSIT.ID AS DEPOSIT_ID
FROM COURTESY_CHECK
INNER JOIN CHECK_DEPOSIT ON CHECK_DEPOSIT.COURTESY_CHECK_ID = COURTESY_CHECK.ID
Edit ... this CASE statement with outer joins might be more efficient -- I think this would work, too:
SELECT COURTESY_CHECK.CHECK_NUMBER,
CASE WHEN IPAC.DEPOSIT_ID IS NOT NULL THEN COURTESY_CHECK.CHECK_AMOUNT
ELSE NULL END AS [IPAC AMOUNT],
CASE WHEN IPAC.DEPOSIT_ID IS NOT NULL THEN NULL ELSE COURTESY_CHECK.CHECK_AMOUNT
END AS [DEPOSITED AMOUNT],
CHECK_DEPOSIT.ID AS DEPOSIT_ID
FROM COURTESY_CHECK
INNER JOIN CHECK_DEPOSIT ON CHECK_DEPOSIT.COURTESY_CHECK_ID = COURTESY_CHECK.ID
LEFT JOIN DEPOSIT ON CHECK_DEPOSIT_ID = DEPOSIT.ID
LEFT JOIN IPAC ON DEPOSIT.ID = IPAC.DEPOSIT_ID

Related

Access Subquery On mulitple conditions

This SQL query needs to be done in ACCESS.
I am trying to do a subquery on the total sales, but I want to link the sale to the province AND to product. The below query will work with one or the other: (po.product_name = allp.all_products) AND (p.province = allp.all_province); -- but it will no take both.
I will be including every month into this query, once I can figure out the subquery on with two criteria.
Select
p.province as [Province],
po.product_name as [Product],
all_price
FROM
(purchase_order po
INNER JOIN person p
on p.person_id = po.person_id)
left join
(
select
po1.product_name AS [all_products],
sum(pp1.price) AS [all_price],
p1.province AS [all_province]
from (purchase_order po1
INNER JOIN product pp1
on po1.product_name = pp1.product_name)
INNER JOIN person p1
on po1.person_id = p1.person_id
group by po1.product_name, pp1.price, p1.province
)
as allp
on (po.product_name = allp.all_products) AND (p.province = allp.all_province);
Make the first select sql into a table by giving it an alias and join table 1 to table 2. I don't have your table structure or data to test it but I think this will lead you down the right path:
select table1.*, table2.*
from
(Select
p.province as [Province],
po.product_name as [Product]
--removed this ,all_price
FROM
(purchase_order po
INNER JOIN person p
on p.person_id = po.person_id) table1
left join
(
select
po1.product_name AS [all_products],
sum(pp1.price) AS [all_price],
p1.province AS [all_province]
from (purchase_order po1
INNER JOIN product pp1
on po1.product_name = pp1.product_name)
INNER JOIN person p1
on po1.person_id = p1.person_id
group by po1.product_name, pp1.price, p1.province --check your group by, I dont think you want pp1.price here if you want to aggregate
) as table2 --changed from allp
on (table1.product = table2.all_products) AND (table1.province = table2.all_province);

SQL joins not giving me correct totals

I'm trying to get a report for figures from multiple transaction tables. Each table has a foreign key that is a lookup for the day it was taken on, and what location it was taken at called Site_Lookup_Id. It's giving me figures that are much larger than they should be.
#Site_Lookup_Ids dbo.Id_List READONLY
SELECT SL.Site_Lookup_Id, D.[Start],SUM(I.Amount) AS Income,
SUM(P.Amount) AS Payouts,SUM(DP.Amount) AS Deposit
FROM CashUp_Site_Lookup SL
INNER JOIN #Site_Lookup_Ids IDs ON Ids.Id = SL.Site_Lookup_Id
INNER JOIN CashUp_Day D ON SL.Day_Id = D.Day_Id
LEFT JOIN CashUp_Deposit DP ON DP.Redeemed_Site_Lookup_Id = SL.Site_Lookup_Id
AND DP.No_Show != 1
LEFT JOIN CashUp_Income I ON I.Site_Lookup_Id = SL.Site_Lookup_Id
LEFT JOIN CashUp_Payout P ON P.Site_Lookup_Id = SL.Site_Lookup_Id
GROUP BY SL.Site_Lookup_Id, D.[Start]
Not all sums will have a value as some days no transactions for a given table will be taken on the day - In this the value should be zero.
The issue is that running this gives me crazy high values - £7500 for income against one day, when if I do a simple check it's £40 for that day like so.
SELECT SUM(Amount) FROM Cashup_Income WHERE Site_Lookup_Id IN (values...)
Maybe something like...
It really depends on the relationships and when you want the values to be summed.
SELECT SL.Site_Lookup_Id
, D.[Start]
, SUM(I.Amount) over (partition by Key of I table) AS Income
, SUM(P.Amount) over (partition by Key of P table) AS Payouts
, SUM(DP.Amount) over (partition by Key of DP Table) AS Deposit
FROM CashUp_Site_Lookup SL
INNER JOIN #Site_Lookup_Ids IDs ON Ids.Id = SL.Site_Lookup_Id
INNER JOIN CashUp_Day D ON SL.Day_Id = D.Day_Id
LEFT JOIN CashUp_Deposit DP ON DP.Redeemed_Site_Lookup_Id = SL.Site_Lookup_Id
AND DP.No_Show != 1
LEFT JOIN CashUp_Income I ON I.Site_Lookup_Id = SL.Site_Lookup_Id
LEFT JOIN CashUp_Payout P ON P.Site_Lookup_Id = SL.Site_Lookup_Id
GROUP BY SL.Site_Lookup_Id, D.[Start]
The problem stems from the fact that your tables are 1:M Causing values to repeat. These repeated values are then getting added to your sum. The joins cause this issue. So I think you can sum using a partition to eliminate the duplicates or:
Use derived tables or a CTE and sum the values BEFORE you join.
Using CTE's (Common Table Expressions)
WITH DP AS (SELECT sum(Amount) As Deposit
, Redeemed_Site_Lookup_ID
FROM CashUp_Deposit
WHERE No_Show !=1
GROUP BY Redeemed_Site_Lookup_ID),
I AS (SELECT sum(Amount) as Income
, Site_Lookup_Id
FROM CashUp_Income
GROUP BY Site_Lookup_Id),
P AS (SELECT sum(Amount) as Payouts
, Site_Lookup_Id
FROM CashUp_Payout
GROUP BY Site_Lookup_Id)
SELECT SL.Site_Lookup_Id
, D.[Start]
, Income
, Payouts
, Deposit
FROM CashUp_Site_Lookup SL
INNER JOIN #Site_Lookup_Ids IDs
ON Ids.Id = SL.Site_Lookup_Id
INNER JOIN CashUp_Day D
ON SL.Day_Id = D.Day_Id
LEFT JOIN DP
ON DP.Redeemed_Site_Lookup_Id = SL.Site_Lookup_Id
LEFT JOIN I
ON I.Site_Lookup_Id = SL.Site_Lookup_Id
LEFT JOIN P
ON P.Site_Lookup_Id = SL.Site_Lookup_Id
Presumably, you are generating a Cartesian product with your joins. Because you have no filtering, do the aggregation before the joins:
LEFT JOIN
(SELECT DP.Redeemed_Site_Lookup_Id, SUM(DP.Amount) AS Deposit
FROM CashUp_Deposit DP
WHERE DP.No_Show != 1
GROUP BY DP.Redeemed_Site_Lookup_Id
) DP
ON DP.Redeemed_Site_Lookup_Id = SL.Site_Lookup_Id LEFT JOIN
(SELECT I.Site_Lookup_Id, SUM(I.Amount) AS Income
FROM CashUp_Income I
GROUP BY I.Site_Lookup_Id
) I
ON I.Site_Lookup_Id = SL.Site_Lookup_Id LEFT JOIN
(SELECT P.Site_Lookup_Id, SUM(P.Amount) AS Payout
FROM CashUp_Payout P
GROUP BY I.Site_Lookup_Id
) P
ON P.Site_Lookup_Id = SL.Site_Lookup_Id
Then adjust the rest of your query to remove the GROUP BY and SUM()s.

Access Query and attributes

The setup is this: every location has many different accounts. Some are supplier only accounts, some are not. Each account has many bills associated with it.
I need to do one of two things:
Create a dynamic attribute in the location table that will tell me if the location is associated with an account (or many) that are supplier only. Should be a true/false attribute.
OR
Create a query that will return all the bills for all the locations that are associated with a supplier only account. I do not want a query that only returns bills from supplier only accounts.
Thanks for you help!
Here's the answer:
Location3PS Query:
SELECT DISTINCT Locations.Number
FROM Locations INNER JOIN Accounts ON Locations.Number = Accounts.[Location Num]
WHERE (((Accounts.[Supplier Only?])=True));
Final Query to Get Bills:
SELECT Bills.*, Location3PS.*
FROM
Location3PS INNER JOIN
(
Locations INNER JOIN
(
Accounts INNER JOIN Bills
ON Accounts.[Account Number] = Bills.[Account Number]
)
ON Locations.Number = Accounts.[Location Num]
)
ON Location3PS.Number = Locations.Number;
You can accomplish this without involving the Locations table, e.g.:
select b.* from
(bills b inner join accounts a on b.[account number] = a.[account number])
inner join
(select distinct c.[location num] from accounts c where c.[supplier only?] = true) l
on a.[location num] = l.[location num]
Alternatively, you can use a correlated subquery, e.g.:
select b.*
from bills b inner join accounts a on b.[account number] = a.[account number]
where exists
(select 1 from accounts c where c.[location num] = a.[location num] and c.[supplier only?] = true)

Values Inexplicably multiplying by a power of 15 when performing a join?

So I started building a query that joins 5 separate tables together to get values to multiply and sum. However, I seem to be facing a rather odd issue. Whenever I attempt to join a certain table to my query, suddenly all of my values are multiplied by 15, the counts, the sums, etc. I'm trying to figure out what is causing all these extra runs. Any ideas?
Full Query
USE Facilities_Database
DECLARE #minimumDate DATE
DECLARE #maximumDate DATE
SET #minimumDate = '2014/12/11'
SET #maximumDate = '2014/12/15'
SELECT tab4.TypeName AS 'Labor Type'
,tab1.Building
,CAST(#minimumDate AS nvarchar(255)) + ' - ' + CAST(#maximumDate AS nvarchar(255)) AS 'Date Range'
,Count(tab1.CHSRNumber) AS 'Number of CHSRs'
,ISNULL(SUM(tab5.[Item Cost] * tab3.[Amount Used]),0) AS 'Total Material Cost'
,ISNULL(SUM(tab2.[Hour Worked] * tab2.[Hourly CHSR Labor Rate]),0) AS 'Total Labor Cost'
FROM [Facilities].[HardwareSupportRequest] tab1
JOIN Facilities.tblCHSRLaborPerCHSR tab2
ON tab1.CHSRNumber = tab2.[CHSR #]
JOIN Facilities.tblMaterialUsed tab3
ON tab1.CHSRNumber = tab3.[CHSR #]
JOIN Facilities.LaborTypes tab4
ON tab2.LaborTypeId = tab4.Id
JOIN Facilities.tblMaterial tab5
ON tab3.MaterialId = tab5.Id
WHERE tab1.ActualCompleteDate BETWEEN #minimumDate AND #maximumDate AND tab4.TypeName IS NOT NULL
GROUP BY tab4.TypeName,Building
ORDER BY Building,tab4.TypeName
Working Query:
USE Facilities_Database
SELECT tab1.Building
,COUNT(*) AS 'CHSR Count'
,SUM(tab2.[Hour Worked] * 40) AS 'Labor Cost'
FROM [Facilities].[HardwareSupportRequest] tab1
INNER JOIN Facilities.tblCHSRLaborPerCHSR tab2 ON
tab1.CHSRNumber = tab2.[CHSR #]
INNER JOIN Facilities.LaborTypes tab3 ON
tab2.LaborTypeId = tab3.Id
--INNER JOIN Facilities.tblMaterialUsed tab4 ON
--tab4.[CHSR #] = tab1.CHSRNumber
--INNER JOIN Facilities.tblMaterial tab5 ON
-- tab4.MaterialId = tab5.Id
WHERE ActualCompleteDate BETWEEN '2014/12/11' AND '2014/12/15'
GROUP BY tab1.Building,tab3.TypeName
The table that causes the problems is tblMaterialsUsed.
Thanks for any assistance.
You've got insufficient JOIN criteria resulting in one row joining to multiple rows.
If the following query results in two different numbers, then you know that JOIN is to blame:
SELECT COUNT(*),COUNT(DISTINCT [CHSR #])
FROM Facilities.tblMaterialUsed
You need to then determine how to exclude the extra records by adding to your JOIN criteria or perhaps aggregating in a subquery first.
Update:
To aggregate first you can use a cte or subquery to aggregate by CHSR # then join to that cte/subquery:
;WITH Materials AS (SELECT mat.[CHSR #]
,ISNULL(SUM(tab5.[Item Cost] * tab3.[Amount Used]),0) AS Total_Material_Cost
FROM Facilities.tblMaterialUsed tab3
JOIN Facilities.tblMaterial tab5
ON tab3.MaterialId = tab5.Id
GROUP BY mat.[CHSR #]
)
SELECT tab4.TypeName AS 'Labor Type'
,tab1.Building
,CAST(#minimumDate AS nvarchar(255)) + ' - ' + CAST(#maximumDate AS nvarchar(255)) AS 'Date Range'
,Count(tab1.CHSRNumber) AS 'Number of CHSRs'
,SUM(mat.Total_Material_Cost) AS 'Total Material Cost'
,ISNULL(SUM(tab2.[Hour Worked] * tab2.[Hourly CHSR Labor Rate]),0) AS 'Total Labor Cost'
FROM [Facilities].[HardwareSupportRequest] tab1
JOIN Facilities.tblCHSRLaborPerCHSR tab2
ON tab1.CHSRNumber = tab2.[CHSR #]
JOIN Facilities.LaborTypes tab4
ON tab2.LaborTypeId = tab4.Id
JOIN Materials mat
ON tab1.CHSRNumber = mat.[CHSR #]
WHERE tab1.ActualCompleteDate BETWEEN #minimumDate AND #maximumDate AND tab4.TypeName IS NOT NULL
GROUP BY tab4.TypeName,Building
ORDER BY Building,tab4.TypeName
If adding a JOIN multiplies the results of GROUP BY operations, then the JOIN is returning more than 1 row per JOIN criteria. Either narrow it down (maybe you are missing 1 or more JOIN fields?) or add more fields to the GROUP BY to change the granularity of what is being aggregated.
The issue is that you have a list of Materials User per each [CHSR #]. Those rows cause a "Cartesian Product" such that the other rows are duplicated per each row in tblMaterialUsed. Hence the Total Material Cost field was probably correct while the Number of CHSRs and Total Labor Cost were multiplied. Essentially, you need to group data at the same level of granularity, which means 1-to-1 across CHSRNumber / [CHSR #]
The following should solve this issue. If it doesn't, that would be due to more than 1 row per CHSRNumber / [CHSR #] in the main query (which is getting JOINed with the 1 row per CHSRNumber / [CHSR #] of the material CTE). In this case, you would apply the same theory to the main query by creating a second CTE for that aggregation and then just JOIN both of those results in the new main query. (and I have updated the query below to incorporate that change as it is doubtful that it wouldn't be needed)
;WITH material AS
(
SELECT mu.[CHSR #],
ISNULL(SUM(mtrl.[Item Cost] * mu.[Amount Used]),0) AS [MaterialCost]
FROM Facilities.tblMaterialUsed mu
INNER JOIN Facilities.tblMaterial mtrl
ON mu.MaterialId = mtrl.Id
GROUP BY mu.[CHSR #]
), labour AS
(
SELECT tab1.CHSRNumber,
tab4.TypeName,
tab1.Building,
ISNULL(SUM(tab2.[Hour Worked] * tab2.[Hourly CHSR Labor Rate]),0) AS [LaborCost]
FROM [Facilities].[HardwareSupportRequest] tab1
JOIN Facilities.tblCHSRLaborPerCHSR tab2
ON tab1.CHSRNumber = tab2.[CHSR #]
JOIN Facilities.LaborTypes tab4
ON tab2.LaborTypeId = tab4.Id
WHERE tab1.ActualCompleteDate BETWEEN #minimumDate AND #maximumDate
AND tab4.TypeName IS NOT NULL
GROUP BY tab1.CHSRNumber, tab4.TypeName, tab1.Building
)
SELECT labour.TypeName AS [Labor Type],
labour.Building,
CAST(#minimumDate AS NVARCHAR(255)) + ' - '
+ CAST(#maximumDate AS NVARCHAR(255)) AS [Date Range],
COUNT(labour.[CHSRNumber]) AS [Number of CHSRs],
SUM(material.[MaterialCost]) AS [Total Material Cost],
SUM(labour.[LaborCost]) AS [Total Labor Cost]
FROM labour
INNER JOIN material
ON labour.CHSRNumber = material.[CHSR #]
GROUP BY labour.TypeName, labour.Building
ORDER BY labour.Building, labour.TypeName;
If you want this in a View, instead use an Inline Table-Valued Functions by adding the following to the beginning:
CREATE FUNCTION GetCosts (#minimumDate DATE, #maximumDate DATE)
RETURNS TABLE
AS RETURN
And
remove the ; before the ;WITH
remove the ORDER BY
Also, it would be a huge benefit if you used acronyms for table aliases instead of tab1, tab2, etc as it would make the query much easier to read, especially given that the same table in both queries isn't even the same tab#.
It appears I can use subqueries to fix this issue
USE Facilities_Database
DECLARE #minimumDate DATE
DECLARE #maximumDate DATE
SET #minimumDate = '2012/12/11'
SET #maximumDate = '2014/12/15'
SELECT LaborTypes.TypeName AS 'Labor Type'
,CHSRs.Building
,CAST(#minimumDate AS nvarchar(255)) + ' - ' + CAST(#maximumDate AS nvarchar(255)) AS 'Date Range'
,Count(CHSRs.CHSRNumber) AS 'Number of CHSRs'
,ISNULL(SUM(matUsed.cost),0) AS 'Total Material Cost'
,ISNULL(SUM(Labor.[Hour Worked] * Labor.[Hourly CHSR Labor Rate]),0) AS 'Total Labor Cost'
FROM [Facilities].[HardwareSupportRequest] CHSRs
JOIN Facilities.tblCHSRLaborPerCHSR Labor
ON CHSRs.CHSRNumber = Labor.[CHSR #]
JOIN (SELECT ROUND(SUM(matU.[Amount Used] * mat.[Item Cost] * 1.05417 * 1.15),2) AS cost, [CHSR #]
FROM Facilities.tblMaterialUsed matU
JOIN Facilities.tblMaterial mat ON
matU.MaterialId = mat.Id
GROUP BY matU.[CHSR #]) matUsed ON
matUsed.[CHSR #] = CHSRs.CHSRNumber
--JOIN Facilities.tblMaterialUsed tab3
-- ON CHSRs.CHSRNumber = tab3.[CHSR #]
JOIN Facilities.LaborTypes LaborTypes
ON Labor.LaborTypeId = LaborTypes.Id
--JOIN Facilities.tblMaterial tab5
-- ON tab3.MaterialId = tab5.Id
WHERE CHSRs.ActualCompleteDate BETWEEN #minimumDate AND #maximumDate AND LaborTypes.TypeName IS NOT NULL
GROUP BY LaborTypes.TypeName,Building
ORDER BY Building,LaborTypes.TypeName

How could I combine these 3 T-SQL statements into one?

I have 3 queries that I want to combine. 1 query is for total sales, 1 is for canceled orders, and 1 is for orders that don't include specific product types. Just need the total sales $$ to output in a table format as they are now. The only thing that changes between the 3 is the where statement. Thanks!
Edit: I realize I said "Just need the total sales $$" ... what I meant was I just need the sales $$ for each query in one table. So $x, $y, $z ... x is the total sales, y is the sales dollars that got cancelled, and z is the sales dollars for the specific items.
SELECT Sum((Items.Total+Items.Shipping)*OrderDetails.Quantity) AS Total
FROM Promo INNER JOIN (Orders INNER JOIN (Items INNER JOIN OrderDetails ON Items.ItemCode = OrderDetails.ItemCode) ON Orders.OrderNumber = OrderDetails.OrderNumber) ON Promo.Promo = Orders.Promo
WHERE ((Promo.OfferType)='Sale') AND ((Items.Date) Between '6/1/2010' And '12/31/2011');
SELECT Sum((Items.Total+Items.Shipping)*OrderDetails.Quantity) AS Canceled
FROM Promo INNER JOIN (Orders INNER JOIN (Items INNER JOIN OrderDetails ON Items.ItemCode = OrderDetails.ItemCode) ON Orders.OrderNumber = OrderDetails.OrderNumber) ON Promo.Promo = Orders.Promo
WHERE (((Promo.OfferType)='Sale') AND ((Items.Date) Between '6/1/2010' And '12/31/2011') AND ((Items.Status)="Canceled"));
SELECT Sum((Items.Total+Items.Shipping)*OrderDetails.Quantity) AS BadItems
FROM Promo INNER JOIN (Orders INNER JOIN (Items INNER JOIN OrderDetails ON Items.ItemCode = OrderDetails.ItemCode) ON Orders.OrderNumber = OrderDetails.OrderNumber) ON Promo.Promo = Orders.Promo
WHERE (((Promo.OfferType)='Sale') AND ((Items.Date) Between '6/1/2010' And '12/31/2011') AND ((Items.ProductType)<>2) AND ((Items.ProductType)<>6));
Thanks!
If you want the results on 1 row:
SELECT Total, Canceled, BadItems
FROM Query1, Query2, Query3
And if you want the results in 1 column, use a UNION:
Query1
UNION
Query2
UNION
Query3
Updated to reflect question clarification:
SELECT Sum(CASE WHEN Items.Status <> 'Canceled' AND Items.ProductType = 4 THEN (Items.Total+Items.Shipping)*OrderDetails.Quantity ELSE 0 END) AS Total ,
Sum(CASE WHEN Items.Status = 'Canceled' AND Items.ProductType = 4 THEN (Items.Total+Items.Shipping)*OrderDetails.Quantity ELSE 0 END) AS Canceled,
Sum(CASE WHEN Items.ProductType <> 4 THEN (Items.Total+Items.Shipping)*OrderDetails.Quantity ELSE 0 END) AS BadItems,
FROM Promo INNER JOIN (Orders INNER JOIN (Items INNER JOIN OrderDetails ON Items.ItemCode = OrderDetails.ItemCode) ON Orders.OrderNumber = OrderDetails.OrderNumber) ON Promo.Promo = Orders.Promo
WHERE ((Promo.OfferType)='Sale') AND ((Items.Date) Between '9/1/2010' And '12/31/2010');
try to use a procedure which will accept three values as input which will suite your were statements and it will give results in one table as want. if you are stuck let me know , i will help.