My SQL is double counting 'Fund1Amount' and 'Fund2Amount' and 'TotalAllDonations' I have a record where the values of the FundAmount1 should = 10 and FundAmount2 should = 20 but they equal 20 & 40 and the total is double. I am using INNER JOINs twice on the same table abc_donationdetail which i am not sure if this is the problem.
SELECT
C.FirstName, C.LastName,
SUM(D.abc_totalamount) AS TotalAllDonations,
SUM(CASE WHEN DBU.abc_fundidname = 'Fund1' THEN DBU.abc_amount END) AS Fund1Amount,
SUM(CASE WHEN DBE.abc_fundidname = 'Fund2' THEN DBE.abc_amount END) AS Fund2Amount
FROM
Contact C
INNER JOIN
Account A ON C.parentcustomerid = A.accountid
INNER JOIN
Account PA ON A.parentaccountid = PA.accountid
INNER JOIN
abc_donation D ON D.abc_person = C.contactid
LEFT JOIN
abc_donationdetail DBU ON DBU.abc_donationid = D.abc_donationid
AND DBU.abc_fundidname= 'Fund1'
LEFT JOIN
abc_donationdetail DBE ON DBE.abc_donationid = D.abc_donationid
AND DBE.abc_fundidname = 'Fund2'
LEFT JOIN
abc_mmcs GD ON GD.abc_donor = C.contactid
LEFT JOIN
sab_item LIBU ON LIBU.sab_itemid = GD.abc_companyid
AND LIBU.sab_name = 'Fund1'
LEFT JOIN
sab_item LIBE ON LIBE.sab_itemid = GD.abc_companyid
AND LIBE.sab_name = 'Fund2'
where C.StateCode = 0 AND (GD.abc_enddate > GETDATE() or GD.abc_enddate IS NULL)
group by C.abc_memberid, C.FirstName, C.LastName , C.StateCode, A.name, A.parentaccountidname, A.dd_number, PA.dd_number, C.parentcustomeridname
order by C.lastname
Current
FN LN Total Fund1 Fund2
James Brown 70 40 30
Phillip Smith 160 60 100
Peter Jones 80 40 40
Vincent Limp 48 48 NULL
Michael Collins 60 60 NULL
Desired
FN LN Total Fund1 Fund2
James Brown 35 20 15
Phillip Smith 80 30 50
Peter Jones 40 20 20
Vincent Limp 24 24 NULL
Michael Collins 30 30 NULL
Any help would be great.
Thanks
If the problem is only in duplicates, than simply make a subquery:
Select fld, sum(value)
from (select distinct fld, value from tbl) as a
I can't say much here as there are lots of tables joined here and I don't know their schema. At most, I can suggest you to add group by with person's id and fund id as it'll remove the duplicates.
SELECT
C.FirstName, C.LastName,
SUM(D.abc_totalamount) AS TotalAllDonations,
SUM(CASE WHEN DBU.abc_fundidname = 'Fund1' THEN DBU.abc_amount END) AS Fund1Amount,
SUM(CASE WHEN DBU.abc_fundidname = 'Fund2' THEN DBU.abc_amount END) AS Fund2Amount
FROM
Contact C
INNER JOIN
Account A ON C.parentcustomerid = A.accountid
INNER JOIN
Account PA ON A.parentaccountid = PA.accountid
INNER JOIN
abc_donation D ON D.abc_person = C.contactid
LEFT JOIN
abc_donationdetail DBU ON DBU.abc_donationid = D.abc_donationid
AND (DBU.abc_fundidname= 'Fund1'
OR DBU.abc_fundidname = 'Fund2') //MERGED 2 JOINS
LEFT JOIN
abc_mmcs GD ON GD.abc_donor = C.contactid
LEFT JOIN
sab_item LIBU ON LIBU.sab_itemid = GD.abc_companyid
AND LIBU.sab_name = 'Fund1'
LEFT JOIN
sab_item LIBE ON LIBE.sab_itemid = GD.abc_companyid
AND LIBE.sab_name = 'Fund2'
where C.StateCode = 0 AND (GD.abc_enddate > GETDATE() or GD.abc_enddate IS NULL)
group by C.abc_memberid, C.FirstName, C.LastName , C.StateCode, A.name, A.parentaccountidname, A.dd_number, PA.dd_number, C.parentcustomeridname order by C.lastname
Hope it works!
Related
Given the table Customers, example:
CustomerID FirstName MiddleInitial LastName
64 Abby A Garcia
65 Abby C Mehta
66 Abby E Chandra
67 Abby J Kapoor
68 Abby J Sanchez
69 Abby K Kovár
70 Abby L Sai
71 Abby M Lopez
72 Abby P Gonzalez
73 Abby P Rana
I would like to restrict the access to (table, column, row) as per definition in the other table, let's say m_Customers with definitions such as:
MetadataID Field Type Access
1 Customers table "Group1","Group2","Group3"
2 MiddleInitial column "Group1","Group3"
3 18 row "Group1","Group3"
Based on that, how do you formulate a query which ensures that if you are:
from *Group3" you can't see column MiddleInitials and row with CustomerId = 18
from "Group4" you can't see the data in Customers table
Any ideas?
It seems like your exclusions and inclusions are mixed. You have Group3 included with column Customers and row 18, but Group 4 not included with table Customers. Make your m_Customers table include only those that have access or only those that are restricted -- not both.
It would typically be faster and easier to manage to change your data structure for m_Customers to use a record for every group.
MetadataID Field Type Access
1 Customers table Group1
2 Customers table Group2
3 Customers table Group3
4 MiddleInitial column Group1
5 MiddleInitial column Group3
6 18 row Group1
7 18 row Group3
Here are two options; you can check for performance.
SELECT MAX(col.customerID) AS customerID, MAX(col.FirstName) AS FirstName, MAX(col.MiddleInitial) AS MiddleIntitial, MAX(col.LastName) AS LastName
FROM Customers AS c
INNER JOIN m_Customers AS mRow ON mRow.[Type] = 'row' AND mRow.CustomerID = c.Field AND mRow.Access = #group
LEFT JOIN (
SELECT
IIF(mCol.Field = 'customerID', c.customerID, NULL) AS customerID,
IIF(mCol.Field = 'Firstname', c.FirstName, NULL) AS FirstName,
IIF(mCol.Field = 'MiddleInitial', c.FirMiddleInitialstName, NULL) AS MiddleInitial,
IIF(mCol.Field = 'LastName', c.LastName, NULL) AS LastName
FROM Customers AS c
INNER JOIN m_Customers AS mCol ON mCol.[Type] = 'column' AND mCol.Field = 'MiddleInitial' AND mCol.Access = #group
) AS col ON col.customerID = c.CustomerID
GROUP BY col.customerID, col.FirstName, col.MiddleInitial, col.LastName
or
SELECT customerID.customerID, FirstName.FirstName, MiddleInitial.MiddleInitial, LastName.LastName
FROM Customers AS c
INNER JOIN m_Customers AS mRow ON mRow.[Type] = 'row' AND mRow.CustomerID = c.Field AND mRow.Access = #group
LEFT JOIN (
SELECT c.customerID
FROM Customers AS c
INNER JOIN m_Customers AS mCol ON mCol.[Type] = 'column' AND mCol.Field = 'customerID' AND mCol.Access = #group
) AS customerID ON customerID.customerID = c.customerID
LEFT JOIN (
SELECT c.customerID, c.FirstName
FROM Customers AS c
INNER JOIN m_Customers AS mCol ON mCol.[Type] = 'column' AND mCol.Field = 'FirstName' AND mCol.Access = #group
) AS FirstName ON FirstName.customerID = c.customerID
LEFT JOIN (
SELECT c.customerID, c.MiddleInitial
FROM Customers AS c
INNER JOIN m_Customers AS mCol ON mCol.[Type] = 'column' AND mCol.Field = 'MiddleInitial' AND mCol.Access = #group
) AS MiddleInitial ON MiddleInitial.customerID = c.customerID
LEFT JOIN (
SELECT c.customerID, c.LastName
FROM Customers AS c
INNER JOIN m_Customers AS mCol ON mCol.[Type] = 'column' AND mCol.Field = 'LastName' AND mCol.Access = #group
) AS LastName ON LastName.customerID = c.customerID
Consider changing the name of your column from Type to a non-reserved word.
I have the following query:
SELECT PersonTotalHours.MA, PersonTotalHours.Year, PersonTotalHours.CalendarWeek,
PersonTotalHours.Hours, Person.Name, Person.Lastname
FROM PersonTotalHours
INNER JOIN Person
ON PersonTotalHours.MA = Person.MA;
Which results in the following table:
MA Year CalendarWeek Hours Name Lastname
aA 2000 5 53 aa AA
aA 2000 44 175 aa AA
... ... ... ...
aA 2001 4 226 aa AA
aA 2001 12 87 aa AA
... ... ... ...
bB 2000 1 189 bb BB
bB 2000 35 65 bb BB
... ... ... ...
as you can see, there is no data for some calendar weeks. Is there any way that I can have a row for all calendar weeks(1 to 53) and with hours=0 for the ones that don't exist now?
Edit
I have solve this temporarily by adding the missing row to the table. using a function that is called when the report opens. Still looking for a non-stupid solution.
Create a help table Calendar, storing all possible values. RIGHT JOIN it:
SELECT pth.MA, pth.Year, pth.CalendarWeek,
pth.Hours, p.Name, p.Lastname
FROM PersonTotalHours pth
INNER JOIN Person p
ON pth.MA = p.MA
RIGHT JOIN Calendar c
ON pth.Year = c.Year AND pth.CalendarWeek = c.CalendarWeek
(Using table aliases to spare some typing.)
EDIT: MS Access query attempt, version 1:
SELECT pth.MA, pth.Year, pth.CalendarWeek,
pth.Hours, p.Name, p.Lastname
FROM (PersonTotalHours pth
INNER JOIN Person p
ON pth.MA = p.MA)
RIGHT JOIN Calendar c
ON pth.Year = c.Year AND pth.CalendarWeek = c.CalendarWeek
EDIT: MS Access query attempt, version 2:
SELECT pth.MA, pth.Year, pth.CalendarWeek,
pth.Hours, p.Name, p.Lastname
FROM calendar
left join (PersonTotalHours pth
INNER JOIN Person p ON pth.MA = p.MA)
ON pth.Year = c.Year AND pth.CalendarWeek = c.CalendarWeek
Please check this query.
select PersonTotalHours.MA,PersonTotalHours.YEAR,b.CalendarWeek, PersonTotalHours.Hours, '' Name, '' LastName from PersonTotalHours
right join (
select '' MA, 0 Year, no CalendarWeek, 0 Hours, '' Name, '' Lastname from (
select row_number() over(order by object_id) no from sys.all_objects
) a where no <= 53) b on b.CalendarWeek = Table_1.CalendarWeek
I am not joined person table.
I have a SQL query in which I am using INNER JOIN but I have to calculate the string values ERROR, OK and their total from column d.sd_figure.
This is my SQL query
SELECT
count(d.sd_figure = 'ERROR') AS error,
count(d.sd_figure = 'OK') AS OK count,
count(*) AS total,
m.contr_num, bu.buyer_name,
m.S_remarks, cr.contr_name, br.brand_name,
m.S_date, c.colour_name, s.size_name,
mn.manu_name
FROM
Scanning_M m
INNER JOIN
colour c ON m.color_id = c.colour_id
INNER JOIN
Buyer bu ON m.buyer_id = bu.Byer_ID
INNER JOIN
Scanning_D d ON m.S_id = d.S_id
INNER JOIN
Brand br ON m.Brand_id = br.Brand_id
INNER JOIN
Contract cr ON m.Contr_num = cr.Contr_id
INNER JOIN
Size s ON m.Size_id = s.Size_id
INNER JOIN
Manufacturer mn ON m.Manu_id = mn.manu_id
WHERE
m.S_date BETWEEN '2016-01-13' AND '2016-01-13'
I also want to add count of 'error' , 'OK' and 'Total' too error is in this line
SELECT
count(d.sd_figure = 'ERROR') AS error,
count(d.sd_figure = 'OK') as OK count,
count(*) as total ,
I tried many solution butt returned group by not found etc
SAMPLE DATA DEMANDED FOR d.sd_figure
S_id sd_res sd_figure sd_datetime sd_id
4 456456 ERROR 2016-01-09 03:11:07.000 1
4 456456 ERROR 2016-01-09 03:11:07.000 2
4 456456 ERROR 2016-01-09 03:11:07.000 3
6 123 ERROR 2016-01-09 10:54:47.000 22
6 123 ERROR 2016-01-09 10:54:47.000 23
6 123 ERROR 2016-01-09 10:54:47.000 24
6 123 ERROR 2016-01-09 10:54:48.000 25
6 123 ERROR 2016-01-09 10:54:48.000 26
Untested, but should be something like this:
SELECT sum(CASE WHEN d.sd_figure = 'ERROR' THEN 1 ELSE 0 END) AS error
,sum(CASE WHEN d.sd_figure = 'OK' THEN 1 ELSE 0 END) AS [OK count]
,count(*) AS total
,m.contr_num
,bu.buyer_name
,m.S_remarks
,cr.contr_name
,br.brand_name
,m.S_date
,c.colour_name
,s.size_name
,mn.manu_name
FROM Scanning_M m
INNER JOIN colour c ON m.color_id = c.colour_id
INNER JOIN Buyer bu ON m.buyer_id = bu.Byer_ID
INNER JOIN Scanning_D d ON m.S_id = d.S_id
INNER JOIN Brand br ON m.Brand_id = br.Brand_id
INNER JOIN Contract cr ON m.Contr_num = cr.Contr_id
INNER JOIN Size s ON m.Size_id = s.Size_id
INNER JOIN Manufacturer mn ON m.Manu_id = mn.manu_id
WHERE m.S_date BETWEEN '2016-01-13' AND '2016-01-13'
GROUP BY m.contr_num
,bu.buyer_name
,m.S_remarks
,cr.contr_name
,br.brand_name
,m.S_date
,c.colour_name
,s.size_name
,mn.manu_name
TABLE Laptop_Shift_Departments
id Laptop_ID Curr_department Pre_Department
-----|----------|-----------------|----------------
9 71 4 3
10 68 4 3
11 71 5 4
12 68 5 4
User only search PO Number and against this PO_Num there are 2 laptops (Laptop_ID)
Above is my table now i want to get MAX value Against this laptop_ID ID
I have tried this:
SELECT LD.ID AS Laptop_ID,ld.GulfITBarcode,po.ID as PO_ID,PO.PO_Number as PO_Number,D.Department,
D.ID as Crr_DepID1,d2.Department,D2.ID as Pre_DepID2
FROM PO_PURCHASEORDER PO
INNER JOIN PO_Laptop_Master LM
ON LM.PO_ID = PO.ID
INNER JOIN PO_LaptopDetail LD
ON LD.LapTop_Master_ID = LM.ID
INNER JOIN Laptop_Shift_Departments DP
ON DP.Laptop_Detail_ID = LD.ID
inner join Laptop_Departments d
on d.ID = DP.Current_Dep_ID
inner join Laptop_Departments d2
on d2.ID = DP.Previous_Dep_ID
WHERE PO_NUMBER = '5258'
AND
LD.ID IN (select Max(cSh.id) from Laptop_Shift_Departments cSh)
But it is not working
MY output should be like this:
id Laptop_ID Curr_department Pre_Department
-----|----------|-----------------|----------------
11 71 5 4
12 68 5 4
You'll want to use the 'Group By' function at the end of the fields you want to group by and the 'Max' function in the Select on the columns you want the 'Max' (or 'Min' or 'Avg'). Should look something like this:
SELECT
LD.ID AS Laptop_ID
,ld.GulfITBarcode
,po.ID as PO_ID
,PO.PO_Number as PO_Number
,D.Department
,MAX(D.ID) as Crr_DepID1
,d2.Department
,MAX(D2.ID) as Pre_DepID2
FROM PO_PURCHASEORDER PO
INNER JOIN PO_Laptop_Master LM
ON LM.PO_ID = PO.ID
INNER JOIN PO_LaptopDetail LD
ON LD.LapTop_Master_ID = LM.ID
INNER JOIN Laptop_Shift_Departments DP
ON DP.Laptop_Detail_ID = LD.ID
inner join Laptop_Departments d
on d.ID = DP.Current_Dep_ID
inner join Laptop_Departments d2
on d2.ID = DP.Previous_Dep_ID
WHERE PO_NUMBER = '5258'
AND LD.ID IN (select Max(cSh.id) from Laptop_Shift_Departments cSh)
AND DP.Current_Dep_ID = 5
GROUP BY
LD.ID
,ld.GulfITBarcode
,po.ID
,PO.PO_Number
,D.Department
,d2.Department
(Having not seen the table structure I'm not sure as to the rest of the query. Hope this helps.)
My question, is there a faster way to the following query?
I'm using ORACLE 10g
Say i have a table Manufacturer and Car, and i want to count all occurrences of the column 'Car.Name'. here is How i'd do it:
SELECT manuf.Name, COUNT(car1.Name), COUNT(car2.Name), COUNT(car3.Name)
FROM Manufacturer manuf
LEFT JOIN (SELECT * FROM Car c where c.Name = 'Ferrari1') car1 ON manuf.PK = car1.ManufPK
LEFT JOIN (SELECT * FROM Car c where c.Name = 'Ferrari2') car2 ON manuf.PK = car2.ManufPK
LEFT JOIN (SELECT * FROM Car c where c.Name = 'Ferrari3') car3 ON manuf.PK = car3.ManufPK
GROUP BY manuf.Name
Wanted Results:
Manufacturer | Ferrari1 | Ferrari2 | Ferrari3
----------------------------------------------
Fiat | 1 | 0 | 5
Ford | 2 | 3 | 0
I tried this with few LEFT JOINs, and it worked fine. But when i added a lot (like 90+), it was ultra slow (more than 1 minute).
My question, is there a faster way to do this query?
If you are happy to see the cars counted down the page, try:
select m.Name manufacturer_name,
c.Name car_name,
count(*)
from Manufacturer m
left join Car c
on m.PK = c.ManufPK and c.Name in ('Ferrari1','Ferrari2','Ferrari3')
group by m.Name, c.Name
If you need to see individual cars across the page, try:
select m.Name manufacturer_name,
sum(case c.Name when 'Ferrari1' then 1 else 0 end) Ferrari1_Count,
sum(case c.Name when 'Ferrari2' then 1 else 0 end) Ferrari2_Count,
sum(case c.Name when 'Ferrari3' then 1 else 0 end) Ferrari3_Count
from Manufacturer m
left join Car c
on m.PK = c.ManufPK and c.Name in ('Ferrari1','Ferrari2','Ferrari3')
group by m.Name
SELECT manuf.Name, COUNT(DISTINCT c.Name)
FROM Manufacturer manuf
LEFT JOIN Car c ON manuf.PK = c.ManufPK
GROUP BY manuf.Name
OR depending on your needs
SELECT manuf.Name, c.Name, COUNT(*) Cnt
FROM Manufacturer manuf
LEFT JOIN Car c ON manuf.PK = c.ManufPK
GROUP BY manuf.Name, c.Name
PS: Your question is not very clear. Provide some wanted resultset to refine the answer
You can also try this:
SELECT manuf.Name
, car1.cnt AS Ferrari1
, car2.cnt AS Ferrari2
, car3.cnt AS Ferrari3
FROM
Manufacturer AS manuf
LEFT JOIN
( SELECT ManufPK, COUNT(*) AS cnt
FROM Car
WHERE Name = 'Ferrari1'
GROUP BY ManufPK
) AS car1
ON car1.ManufPK = manuf.PK
LEFT JOIN
( SELECT ManufPK, COUNT(*) AS cnt
FROM Car
WHERE Name = 'Ferrari2'
GROUP BY ManufPK
) AS car2
ON car2.ManufPK = manuf.PK
LEFT JOIN
( SELECT ManufPK, COUNT(*) AS cnt
FROM Car
WHERE Name = 'Ferrari3'
GROUP BY ManufPK
) AS car3
ON car3.ManufPK = manuf.PK
ORDER BY manuf.Name