show rows with no data in access - sql

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.

Related

Values from a table that are not in another one

I have two tables, A and B.
A
ID age
1 24
2 25
45 22
B
ID school
34 school1
1 school2
I want to select IDs that are in B but not in A.
I wrote
Select distinct bb.school
From B as bb
Left outer join A as aa
On bb.ID=aa.ID
inner join C as cc
On bb.school=cc.school
This code returns exactly the same number of rows that I would have with an inner join instead of left outer join.
Am I doing something wrong?
Try using not in;
Select * From A Where ID Not In ( Select ID From B )

SQL query to full columns without defining it in Group By and optimize the Inner Join

one contain multiple columns and test two tables have one columns.
Table: Client
Name age Benefit Id code value
Tom 33 AA 0A 1 12
Tom 33 AB 0C 1 13
Tom 33 AA 0C 5 11
Sam 31 CC 0B 3 10
Rik 28 EE 0D 5 9
Table2: Sell
Code1
1
4
Table3: tip
Code2
5
6
I want output as Name,Age, Benefit, Id and Code, which code present in both table "sell" and "tip".
Name Age Benefit Id code Approved
Tom 33 AA 0A 1 7
Tom 33 AA 0C 5 11
Code I have written as
------Break code-----------
Create table #temp1 as
select c.* from Client c inner join Sell s on c.code1 = s.code
where Benifit= AA
Create table #temp2 as
select c.* from Client c inner join Sell s on c.code2 = s.code
where Benifit= AA
Create table #combine as
select ss.* ,
,case when ss.value > 5 then ss.value- 5 Else 0 approved
from #temp1 ss inner join #temp2 ff
On ss.Name= ff.Name
AND ss.Age= ff.Age
where Benifit= 'AA'
Group by ss.Name Age
------------------------------------------------
----Since 3 table are created with repeated logic, I have put Above code is put into one code, even thought it is not optimized ----------------
select ss.Name, ss.age
,case when ss.value > 5 then ss.value- 5 Else 0 approved
from
(select * from Client c inner join Sell s on c.code1 = s.code
where Benifit= AA) ss
inner join
(select * from Client cc inner join Tip t on cc.code2 = t.code
where Benifit= AA) ff
On ss.Name= ff.Name
AND ss.Age= ff.Age
Group by Name Age
So, I have two problem:
I want Benefit, Id, code and value beside Name and Age, since current query not allow to do that as 'Group By' is used
I am using two select multiple inner join as below
a. (select * from Client c inner join Sell s on c.code = s.code1
where Benifit= AA) ss
b. (select * from Client cc inner join Tip t on cc.code2 = t.code
where Benifit= AA) ff
but I don't want my code to repeatedly use the same code as above is repeated.
A new column Approved is created by subtracting 5 from Value column
Note: The output will Inner join based on "Name" and "Age" between
Inner join of Client & Sell
Inner join between Client & Tip
Please suggest.
Note I want Name, Age having code in both 'Sell' and 'Tip' where Benifit= AA Although output will be from "Sell".
I think you want a query like this -
SELECT C.Name, C.Age, C.Benefit, C.Id, C.Code, (C.Value - 5) Approved
FROM Client C
INNER JOIN Sell S ON C.Code = S.Code1
INNER JOIN Tip T ON S.Code1 = T.Code2
WHERE C.Benefit = 'AA'

SQL Sum double counting

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!

SQL: create a recordset by repeating the output of one query for every record of a second query

I have a query that returns records as below
vw_EmployeeReferenceNumbers
NAME Number
---- ------
AA 123
AA 234
AA 456
I have another table that returns records like so
AllEmployees
AllNames
----------
AA
BB
CC
I want to output a recordset like so
NAME Number
---- ------
AA 123
AA 234
AA 456
BB 123
BB 234
BB 456
CC 123
CC 234
CC 456
I dont want to use Cursors at all. I cant modify the view vw_EmployeeReferenceNumbers or the table AllEmployees. Can this be done in SQL?
What I have so far that doesn't work is:
select name, number
from
(select Name, number, 1 as id from vw_EmployeeReferenceNumbers
) as A
left join
(select name, 1 as id from AllEmployees
) as B
on A.id = B.id
Use cross join:
select e.name, ern.number
from AllEmployees e cross join
vw_EmployeeReferenceNumbers ern;
SELECT e.name,
ern.number
FROM AllEmployees e INNER JOIN
EmployeeReferenceNumbers ern ON 1=1
ORDER BY e.name

cross joining two tables

I have a table that looks like this, lets call this table B.
id boardid schoolid subject cnt1 cnt2 cnt3 ....
=================================================================
1 20 21 f
2 20 21 r
3 20 21 w
4 20 21 m
5 20 30 r
6 20 30 w
7 20 30 m
Suppose the counts are just integers. Notice that there is no subject = f for schoolid = 30. Similarly, for most schools, some subject dosnt exist. You might have a schoolid that has just r, w or some that are just r, m, f..
So what I want to do is have 4 consistent rows for each school, and the row that dosnt exist I want dummy values. I thought about creating a secondary table
drop table #A
Select * into #A FROM
(
select [subject_s] = 'r', orderNo = 1
union all
select [subject_s] = 'w', orderNo = 2
union all
select [subject_s] = 'm', orderNo = 3
union all
select [subject_s] = 'f', orderNo = 4
) z
and doing some joins on them, but I've gotten NO where. I've tried inner join, left outer, cross join, everything. I've even tried to make cartesian product. I think my cartesian product messes up because I have orderno in there so it makes 16 rows per row in the main table. Actually typing this out, I realize if I remove the orderno, apply the cartesian product and then add orderno in later, it might work but I am interested to see what you guys can come up with. I am stumped.
End result
id boardid schoolid subject cnt1 cnt2 cnt3 ....
=================================================================
1 20 21 r
2 20 21 w
3 20 21 m
4 20 21 f
5 20 30 r
6 20 30 w
7 20 30 m
7 20 30 f
Try the following:
SELECT S.boardid, S.schoolid, A.[subject], B.cnt1, B.cnt2, B.cnt3
FROM (SELECT DISTINCT boardid, schoolid FROM YourTable) S
CROSS JOIN #A A
LEFT JOIN YourTable B
ON B.boardid = S.boardid AND B.schoolid = S.schoolid
AND A.[subject] = B.[subject]
Since I do not know which RDBMS you are using I tried the following with sqlite and a simpler table:
sqlite> create table schools (name varchar, subject varchar, teacher varchar);
sqlite> select * from schools;
School1|Maths|Mr Smith
School2|English|Jack
School3|English|Jimmy
School3|Maths|Jane
School4|Computer Science|Bob
sqlite> select
schoolnames.name,
subjects.subject,
ifnull(teachers.teacher, "Unknown")
from (select distinct name from schools) schoolnames
join (select distinct subject from schools) subjects
left join schools teachers
on schoolnames.name = teachers.name
and subjects.subject = teachers.subject;
School1|Maths|Mr Smith
School1|English|Unknown
School1|Computer Science|Unknown
School2|Maths|Unknown
School2|English|Jack
School2|Computer Science|Unknown
School3|Maths|Jane
School3|English|Jimmy
School3|Computer Science|Unknown
School4|Maths|Unknown
School4|English|Unknown
School4|Computer Science|Bob
I'd use:
SELECT
boardid, schoolid, dist_subject, id, cnt1, ...
FROM
(SELECT
boardid, schoolid, dist_subject
FROM
(SELECT
DISTINCT subject AS dist_subject
FROM b ) s full outer join
(SELECT
boardid, schoolid
FROM b
GROUP BY
boardid, schoolid ) g ) sg LEFT OUTER JOIN
b ON
sg.boardID = b.boardID AND
sg.schoolid = b.schoolID
sg.dist_subject = b.subject