How to make subqueries correct - sql

Hey guys, I have some problem with subqueries in SQL. I am using MS Access 2010 and writing sql.
SELECT vak.Name, COUNT(vak.amount) AS [First], COUNT(vak2.amount2) AS [Second]
FROM
(SELECT kon.Name, (Count(icv.CV_ID) / Count(icv.CV_ID)) AS amount
FROM (kon INNER JOIN v ON kon.K_ID = v.K_ID) INNER JOIN icv ON v.Vak_ID = icv.Vak_ID
GROUP BY v.Vak_ID, kon.Name) AS vak,
(SELECT kon.Name, COUNT(v.Vak_ID) AS amount2
FROM (kon INNER JOIN v ON kon.K_ID = v.K_ID) INNER JOIN icv ON v.Vak_ID = icv.Vak_ID
GROUP BY kon.Name) AS vak2
GROUP BY vak.Konkursa_Nosaukums
When I check it in Datasheet view both columns are identical. There are 6 rows in "First" there are values 12, 12, 6, 12, 6, 6. Same values are in "Second" column. When I split this code into 2 pieces and make 2 new queries for testing, "First" Column shows values 2,2,1,2,1,1 and the second query has values of 3,3,1,2,1,1. Both of those columns have correct values when they are separately, but when I combine those, some unknown values appear like 12 (I have no idea where it take such number like 12). When I put line
WHERE vak.amount=vak2.amount2 before last line it shows 2,2,1,2,1,1 in both columns. I guess it takes only from first subquery or something.
How to make those subqueries correctly, so they show values same as when they are written separately?

I think you are missing a join condition and having in apropriate group by ...
SELECT vak.Name, vak.amount AS [First], vak2.amount2 AS [Second]
FROM
(SELECT kon.Name, (Count(icv.CV_ID) / Count(icv.CV_ID)) AS amount
FROM (kon INNER JOIN v ON kon.K_ID = v.K_ID) INNER JOIN icv ON v.Vak_ID = icv.Vak_ID
GROUP BY v.Vak_ID, kon.Name) AS vak,
(SELECT kon.Name, COUNT(v.Vak_ID) AS amount2
FROM (kon INNER JOIN v ON kon.K_ID = v.K_ID) INNER JOIN icv ON v.Vak_ID = icv.Vak_ID
GROUP BY kon.Name) AS vak2
WHERE vak.Name = van2.Name

SELECT vak.Name, vak.amount AS [First], vak2.amount2 AS [Second]
FROM
(SELECT kon.Name, (Count(icv.CV_ID) / Count(icv.CV_ID)) AS amount
FROM (kon INNER JOIN v ON kon.K_ID = v.K_ID) INNER JOIN icv ON v.Vak_ID = icv.Vak_ID
GROUP BY v.Vak_ID, kon.Name) AS vak,
(SELECT kon.Name, COUNT(v.Vak_ID) AS amount2
FROM (kon INNER JOIN v ON kon.K_ID = v.K_ID) INNER JOIN icv ON v.Vak_ID = icv.Vak_ID
GROUP BY kon.Name) AS vak2
WHERE vak.Name = van2.Name

Related

Sum when column values match

How can I sum all of the everything in the amount column if values in policy number column match. This is my current code, but it doesn't work.
select total.*
from (
select p.policyNum,
p.stateID,
p.effectiveDate,
a.claimFreeDiscount,
a.homeownerDiscount,
a.policyZip,
mb.claimnumber,
sum(mb.amount)
from aggressive.dbo.Policy as p
inner join Aggressive.dbo.Auto as a
on p.policyID = a.policyID
left join MicrosoftPowerBI.dbo.ClaimTransactionDetail as mb
on p.policyid = mb.policyid
where p.stateID = 74 and
p.companyID = 10 and
p.status =1
) as total
group by total.mb.Amount

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.

Query for records count from shown rows

select lsd.lsd ,count(reading.infrastructure_id),type.infrastructure_type from public.cpreading_lsd lsd
left join cpreading_infrastructure infra on lsd.id = infra.lsd_id
left join public.cpreading_infrastructure_type type on type.id = infra.infrastructure_type_id
left join cpreading_cp_reading_entry reading on infra.id = reading.infrastructure_id
group by lsd.lsd,type.infrastructure_type
Make the query as an in-line view and select count(*) from the in-line view
Eg:
select count(*) from(
select lsd.lsd
,count(reading.infrastructure_id)
,type.infrastructure_type
from public.cpreading_lsd lsd
left join cpreading_infrastructure infra on lsd.id = infra.lsd_id
left join public.cpreading_infrastructure_type type on type.id = infra.infrastructure_type_id
left join cpreading_cp_reading_entry reading on infra.id = reading.infrastructure_id
group by lsd.lsd,type.infrastructure_type
)x

How to use GROUP BY for a column with an alias?

I have 3 tables
tblVendor, tblVendorItem and tblEventItem.
tblEventItem has the columns Quantity and Price.
I want to show a Vendor's VendorItem on a chart based on their Sales., where Sales will be a calculated as column (Quantity * Price).
I have tried the following query but it´s not working correctly. It says: Invalid column name: Sales.
SELECT tblEventItem.Quantity * tblEventItem.Price AS 'Sales', tblEventItem.VendorItemID, tblVendorItem.Name AS 'VendorItemName'
FROM tblEventService INNER JOIN
tblEventItem ON tblEventService.EventServiceID = tblEventItem.EventServiceID INNER JOIN
tblVendorItem ON tblVendorItem.VendorItemID = tblEventItem.VendorItemID INNER JOIN
tblVendor ON tblVendorItem.VendorID = tblVendor.VendorID
WHERE (tblEventService.ServiceID = 3)
GROUP BY 'Sales'
Use CROSS APPLY or OUTER APPLY for that. This does not affect performance, however it makes code more readable and easier to use.
-- MS SQL
CREATE TABLE #test
(
b INT,
c INT
);
INSERT INTO #test VALUES (1,2), (2,3), (3,4), (4,3)
SELECT s.Sales, COUNT(*) FROM #test a CROSS APPLY (SELECT b*c AS 'Sales') s
GROUP BY s.Sales;
In your case it will be something like:
SELECT
s.Sales ,
tblEventItem.VendorItemID ,
tblVendorItem.Name AS 'VendorItemName'
FROM
tblEventService
INNER JOIN tblEventItem ON tblEventService.EventServiceID = tblEventItem.EventServiceID
INNER JOIN tblVendorItem ON tblVendorItem.VendorItemID = tblEventItem.VendorItemID
INNER JOIN tblVendor ON tblVendorItem.VendorID = tblVendor.VendorID
CROSS APPLY (SELECT tblEventItem.Quantity * tblEventItem.Price Sales) s
WHERE
( tblEventService.ServiceID = 3 )
ORDER BY
'Sales' DESC;
It is very unclear what is need to be grouped by, but hope that with this query you can do your plans.
SELECT tblVendorItem.Name, tblEventItem.Quantity * tblEventItem.Price AS 'Sale'
FROM tblEventService INNER JOIN
tblEventItem ON tblEventService.EventServiceID = tblEventItem.EventServiceID INNER JOIN
tblVendorItem ON tblEventItem.VendorItemID = tblVendorItem.VendorItemID INNER JOIN
tblVendor ON tblVendorItem.VendorID = tblVendor.VendorID
WHERE (tblEventService.VendorID =#VendorID)
GROUP BY tblVendorItem.Name,tblEventItem.Quantity, tblEventItem.Price

selecting the max values based on a count

How can i retrieve the max of each ValueCount based on the firmid. I need the data to be output like so.
My code is below
SELECT
F.FirmID,
F.Name,
DL.ValueId,
DL.ValueName,
count(DL.ValueName) AS ValueCount
FROM
dbo.Jobs AS J
INNER JOIN DimensionValues AS DV ON
DV.CrossRef = J.JobId
INNER JOIN dbo.DimensionLists AS DL ON
DV.ValueId = DL.ValueId
INNER JOIN Firms AS F ON
F.FirmId = J.ClientFirmId
WHERE
DL.DimensionId = 4
GROUP BY
F.FirmID,
F.Name,
DL.ValueName,
DL.ValueId
this produces something like
firmid | value | count
1 1 5
1 2 10
2 3 1
2 1 6
i need to return back the records with 10 and 6.
EDIT : SQL 2005 answer deleted.
Then you could push your results into a temporary table (or table variable) and do something like this...
SELECT
*
FROM
TempTable
WHERE
ValueCount = (SELECT MAX(ValueCount) FROM TempTable AS Lookup WHERE FirmID = TempTable.FirmID)
Or...
SELECT
*
FROM
TempTable
INNER JOIN
(SELECT FirmID, MAX(ValueCount) AS ValueCount FROM TempTable GROUP BY FirmID) AS lookup
ON lookup.FirmID = TempTable.FirmID
AND lookup.ValueCount = TempTable.ValueCount
These will give multiple records if any ValueCount is tied with another for the same FirmID. As such, you could try this...
SELECT
*
FROM
TempTable
WHERE
value = (
SELECT TOP 1
value
FROM
TempTable as lookup
WHERE
FirmID = TempTable.FirmID
ORDER BY
ValueCount DESC
)
For this problem you need to produce the result set of the query in order to determine the Max ValueCount, then you need to do the query again to pull just the records with Max ValueCount. You can do this many way, like repeating the main query as subqueries, and in SQL Server 2005/2008 by using a CTE. I think using the subqueries gets a little messy and would prefer the CTE, but for SQL Server 2000 you don't have that as an option. So, I've used a temp table instead of a CTE. I run it once to get the MaxValueCount and save that into a temp table, then run the query again and join against the temp table to get just the record with MaxValueCount.
create table #tempMax
(
FirmID int,
MaxValueCount int
)
insert #tempMax
SELECT t.FirmID, MAX(t.ValueCount) AS MaxValueCount
FROM (
SELECT F.FirmID, F.Name, DL.ValueId, DL.ValueName
, count(DL.ValueName) AS ValueCount
FROM dbo.Jobs AS J
INNER JOIN DimensionValues AS DV ON DV.CrossRef = J.JobId
INNER JOIN dbo.DimensionLists AS DL ON DV.ValueId = DL.ValueId
INNER JOIN Firms AS F ON F.FirmId = J.ClientFirmId
WHERE DL.DimensionId = 4
GROUP BY F.FirmID, F.Name, DL.ValueName, DL.ValueId) t
SELECT t.FirmID, t.Name, t.ValueID, t.ValueName, t.ValueCount
FROM (
SELECT F.FirmID, F.Name, DL.ValueId, DL.ValueName
, count(DL.ValueName) AS ValueCount
FROM dbo.Jobs AS J
INNER JOIN DimensionValues AS DV ON DV.CrossRef = J.JobId
INNER JOIN dbo.DimensionLists AS DL ON DV.ValueId = DL.ValueId
INNER JOIN Firms AS F ON F.FirmId = J.ClientFirmId
WHERE DL.DimensionId = 4
GROUP BY F.FirmID, F.Name, DL.ValueName, DL.ValueId) t
INNER JOIN #tempMax m ON t.FirmID = m.FirmID and t.ValueCount = m.MaxValueCount
DROP TABLE #tempMax
You should be able to use a derived table for this:
SELECT F.FirmID,
F.Name,
DL.ValueId,
DL.ValueName,
T.ValueCount
FROM Jobs J
INNER JOIN DimensionValues DV
ON DV.Crossref = J.JobID
INNER JOIN DimensionList DL
ON DV.ValueID = DL.ValueID
INNER JOIN Firms F
ON F.FirmID = J.ClientFirmID
--derived table
INNER JOIN (SELECT FirmID, MAX(ValueName) ValueCount FROM DimensionList GROUP BY FirmID) T
ON T.FirmID = F.FirmID
WHERE DL.DimensionId = 4
TBL1 and TBL2 is your query:
SELECT *
FROM TBL1
WHERE
TBL1.ValueCount = (SELECT MAX(TBL2.ValueCount) FROM TBL2 WHERE TBL2.FIRMID = TBL1.FIRMID)