I have two tables in MS-Access, U and R. I have joined them together and want to compare two fields. However, because there are X Tags in both to compare I am getting X lines. As you can see on ID 4 and 2 there are two tags in each table and they are both the same however because of my query I get four lines back because it compares all combinations. I do have a Unique Values set to yes. How can I make this work only getting back two lines for the below examples.
ID U Tag1 R Tag2 Comp
1 100XX7 100XX7 SAME
2 11646L 11644 DIFFERENT
2 11646L 1X05X DIFFERENT
2 15650 11644 DIFFERENT
2 15650 1X05X DIFFERENT
3 5981X 598X0 DIFFERENT
4 19103 19103 SAME
4 19103 19X95 DIFFERENT
4 19X95 19103 DIFFERENT
4 19X95 19X95 SAME
Are you looking for something on the lines of:
SELECT u.ID, u.Tag, r.ID, r.Tag
FROM u INNER JOIN r ON (u.ID = r.ID) AND (u.Tag = r.Tag)
UNION ALL
SELECT u.ID, u.Tag, r.ID, r.Tag
FROM u LEFT JOIN r ON (u.ID = r.ID) AND (u.Tag = r.Tag)
WHERE r.Tag Is Null
The first part shows matched tags, the second part (after Union All) shows tags in u that were not found in r.
add a
GROUP BY id, U.Tag1, R.Tag2, (Comp? perhaps if you need that in your output)
clause to whatever query you're using now :)
Related
I have the following database:
Car: {[CarID, HorsePower, Brand, HeadDesigner]}
DesignsCar:{[CarID, DesID]}
Designer:{[DesID, Name]}
You should note that while every Car has only 1 HeadDesigner, multiple people can design cars (as in work on them).
Say I have 10 cars in my database. For CarID (1..9) only one DesID per CarID in DesignsCar.
However, for carID 10 we have 3 people working on it (carID has 3 entries in DesignsCar because 3 people worked on it).
Say I do this:
select *
from car c
left outer join designscar ds on c.carid = ds.carid
left outer join designer d on frb.persnr = r.persnr
This gives me 12 rows, when I only want 10. The reason why this gives me 12 rows should be clear: for carID 10 we have 3 people working on it (carID has 3 entries in DesignsCar because 3 people worked on it).
I hope I've done a good job explaining this problem, so here comes my question:
How do I modify the query above so I get 10 Rows. For CarID 10 I'd like the 3 designers to be written in one column (like, comma separated but anything works as long it's in one column).
Is that possible?
You need to aggregate the values. Here is one possibility:
select c.*,
array_agg(d.name) as designer_names
from car c left outer join
designscar ds
on c.carid = ds.carid left outer join
designer d
on frb.persnr = r.persnr
group by c.carid ; -- allowed assuming `carid` is the primary key
I have a query is used to display information in a queue and part of that information is showing the amount of child entities (packages and labs) that belong to the parent entity (change). However instead of showing the individual counts of each type of child, they multiply with one another.
In the below case, there are supposed to be 3 labs and 18 packages, however the the multiply with one another and the output is 54 of each.
Below is the offending portion of the query.
SELECT cef.ChangeId, COUNT(pac.PackageId) AS 'Packages', COUNT(lab.LabRequestId) AS 'Labs'
FROM dbo.ChangeEvaluationForm cef
LEFT JOIN dbo.Lab
ON cef.ChangeId = Lab.ChangeId
LEFT JOIN dbo.Package pac
ON (cef.ChangeId = pac.ChangeId AND pac.PackageStatus != 6 AND pac.PackageStatus !=7)
WHERE cef.ChangeId = 255
GROUP BY cef.ChangeId
I feel like this is obvious but it's not occurring to me how to fix it so the two counts are independent of one another like to me they should be. There doesn't seem to be a scenario like this in any of my research either. Can anyone guide me in the right direction?
Because you do multiply source rows by each left join. So sometimes you have more likely cross join here.
SELECT cef.ChangeId, p.Packages, l.Labs
FROM dbo.ChangeEvaluationForm cef
OUTER APPLY(
SELECT COUNT(*) as Labs
FROM dbo.Lab
WHERE cef.ChangeId = Lab.ChangeId
) l
OUTER APPLY(
SELECT COUNT(*) AS Packages
FROM dbo.Package pac
WHERE (cef.ChangeId = pac.ChangeId AND pac.PackageStatus != 6 AND pac.PackageStatus !=7)
) p
WHERE cef.ChangeId = 255
GROUP BY cef.ChangeId
perhaps GROUP BY is not needed now.
From you question its difficult to derive what result do you expect from your query. So I presume you want following result:
+----------+----------+------+
| ChangeId | Packages | Labs |
+----------+----------+------+
| 255 | 18 | 3 |
+----------+----------+------+
Try below query if you are looking for above mentioned result.
SELECT cef.ChangeId, ISNULL(pac.PacCount, 0) AS 'Packages', ISNULL(Lab.LabCount, 0) AS 'Labs'
FROM dbo.ChangeEvaluationForm cef
LEFT JOIN (SELECT Lab.ChangeId, COUNT(*) LabCount FROM dbo.Lab GROUP BY) Lab
ON cef.ChangeId = Lab.ChangeId
LEFT JOIN (SELECT pac.ChangeId, COUNT(*) PacCount FROM dbo.Package pac WHERE pac.PackageStatus != 6 AND pac.PackageStatus !=7 GROUP BY pac.ChangeId) pac
ON cef.ChangeId = pac.ChangeId
WHERE cef.ChangeId = 255
Query Explanation:
In your query you didn't use group by, so it ended up giving you 54 as count which is Cartesian product.
In this query I tried to group by 'ChangeId' and find aggregate before joining tables. So 3 labs and 18 packages will be counted before join.
Your will also notice that I have moved PackageStatus filter before group by in pac table. So unwanted record won't mess with our count.
You start with a particular ChangeId from the dbo.ChangeEvaluationForm table (ChangeId = 255 from your example), then join to the dbo.Lab table. This join makes your result go from 1 row to 3, considering there are 3 Labs with ChangeId = 255. Your problem is on the next join, you are joining all 3 resulting rows from the previous join with the dbo.Package table, which has 18 rows for ChangeId = 255. The resulting count for columns pac.PackageId and lab.LabRequestId will then be 3 x 18 = 54.
To get what you want, there are 2 easy solutions:
Use COUNT DISTINCT instead of COUNT. This will just count the different values of pac.PackageId and lab.LabRequestId and not the repeated ones.
Split the joins into 2 subqueries and join their result (by ChangeId)
I have two tables that I would like to make into one table.
TABLE WASP_COLOR1
ID NAME COLOR CODE
1 WASP01 RED RD
2 WASP04 RED RD
3 WASP19 BLUE BL
TABLE WASP_COLOR2
ID NAME SIZE CODE
1 WASP01 6 RD
2 WASP13 10 BL
3 WASP22 4 BL
I'm a novice and I need clear direction on how to obtain these results. (I want the duplicates merged.)
TABLE WASP_COLOR1
ID NAME COLOR SIZE CODE
1 WASP01 RED 6 RD
2 WASP04 RED RD
3 WASP19 BLUE BL
4 WASP13 10 BL
5 WASP22 4 BL
I tried the following:
SELECT
distinct wasp_color2.name, wasp_color2.size,
wasp_color2.code, wasp_color1.name, wasp_color1.color,
wasp_color1.code
INTO
wasp_color1
FROM
wasp_color2, wasp_color1;
Received error
I tried:
SELECT
distinct wasp_color2.name, wasp_color2.size, wasp_color2.code,
wasp_color1.name, wasp_color1.color, wasp_color1.code
INTO
test
FROM
wasp_color2, wasp_color1;
Received 9 rows instead of 5
I tried:
SELECT
name.wasp_color1, name.wasp_color2, color, size,
code.wasp_color1, code.wasp_color2
INTO
test
FROM wasp_color2, wasp_color1;
This asks for a parameter value, which is a manual entry and cumbersome
I tried:
SELECT
coalesce name.wasp_color1, name.wasp_color2, color,
size, code.wasp_color1, code.wasp_color2
INTO
test
FROM
wasp_color2, wasp_color1 full join;
Received error
Perhaps something like this as MS access doesn't support full outer joins.
What this does is generate two data sets one for wasp_Color1 and those records that match in wasp_Color2 and vice-versa. and then combine's those results into one data set eliminating the duplicates.
For a better understanding of joins: see https://blog.codinghorror.com/a-visual-explanation-of-sql-joins/
Select WC1.Name, WC1.Color, WC2.Size, WC1.Code
FROM wasp_Color1 wc1
LEFT JOIN wasp_color2 wc2
on wc1.Name = WC2.Name
and wc1.code = wc2.code
UNION
Select WC2.Name, WC1.Color, WC2.Size, WC2.Code
FROM wasp_Color1 wc1
RIGHT JOIN wasp_color2 wc2
on wc1.Name = WC2.Name
and wc1.code = wc2.code
This is probably really simple, but I have been struggling. Basically I need to combine 2 different queries:
Get a list of accounts plus some info for each
Based on each of those accounts, get the count of users and forms associated with each.
So given the following table structure:
I want to get back:
Name Users Forms Active
====================================
Child 1 3 4 T
Child 2 4 3 F
So the problem is that I want to query first based on the Master id:
Select * from ACCOUNT where MasterId = 1026
AccntId Name Master Id Active
====================================
2 Child 1 1026 T
3 Child 2 1026 F
Then for each of those returned I would like to get the counts of users and forms.
Select Count(AccntId) as Users from Form Where AccntId=2
And of course all in one query. I have messed around with Joins and Left Joins and the stumbling block in the initial query.
Ok, the final query for anyone who cares turned out to be:
SELECT
A.Id as AccountId, A.Name, A.Active,
(select count(*) as Users FROM UserProfile UP where A.Id = UP.AccountId),
(select count(*) as Forms FROM Form F where A.Id = F.AccountId)
FROM
Account A
WHERE
A.MasterId = 1026
Group By A.Id, A.Name, A.Active
Which gave me ultimately the numbers I was looking for:
AccountId Name Active Users Forms
1 Child T 3 4
5 Child2 F 4 3
Not sure if that is the most efficient or proper approach, but it does work! Thanks for the hints from the commentators
SELECT acc.MasterId, count(up.AccntId) as Users, count(f.AccntId) as Forms
from Account acc
full join UserProfile up
on up.AccntId = acc.AccntId
full join Form f
on f.AccntId = acc.AccntId
-- Where /* Your conditions */
group by acc.MasterId;
This should work.
Edit: joins changed to left join
I have two tables, tblEntities and tblScheduling.
tblEntities:
EntityID ShortName Active
1 Dirtville 1
2 Goldtown 1
3 Blackston 0
4 Cornfelt 1
5 Vick 1
tblScheduling:
ScheduleID EntityID SchedulingYearID
1 1 20
2 1 21
3 2 20
4 3 19
5 5 20
I need a query that will show ALL ACTIVE Entities and their schedule information for a particular ScheduleYearID.
Output should look like (the desired SchedulingYearID in this case is 20):
EntityID ScheduleID
1 1
2 3
4 NULL
5 5
The query that I have written so far is:
SELECT tblEntities.EntityID, tblEntities.ShortName, tblScheduling.ScheduleID
FROM tblScheduling RIGHT OUTER JOIN
tblEntities ON tblScheduling.EntityID = tblEntities.EntityID
WHERE (tblScheduling.SchedulingYearID = #SchedulingYearID)
AND (tblEntities.Active = 1)
ORDER BY tblEntities.EntityID
My problem is that using this query it will not include active entities without schedule information (such as EntityID 4 in the example above). I can write the query to display all active entities and their schedule status fine, but once I start limiting it via the SchedulingYearID I lose those particular entities.
Are there any solutions that I am obviously missing without having to resort to subqueries, cursors, etc.? If not it's not a big deal, I just feel like I am missing something simple here.
Try this... Join conditions are evaluated to produce the intermediate Join result set, and then, (for an outer join), all the rows from the "Outer" side are added back in before moving on... Where conditions are evaluated after all joins are done...
SELECT E.EntityID, E.ShortName, S.ScheduleID
FROM tblEntities E
Left Join tblScheduling S
ON S.EntityID = E.EntityID
And S.SchedulingYearID = #SchedulingYearID
WHERE E.Active = 1
ORDER BY E.EntityID
I change your join order cause I prefer left joins... but it doesn't matter
It's your conditions in the where clause:
(tblScheduling.SchedulingYearID = #SchedulingYearID)
when there is no tblScheduling info this wil always fail. Add
(((tblScheduling.SchedulingYearID = #SchedulingYearID) OR (tblScheduling.SchedulingYearID is null) )
or wathever null condition checking your DB uses.
I think the trouble is that the WHERE clause is filtering out the rows where SchedulingYearID is null. So don't.
SELECT tblEntities.EntityID, tblEntities.ShortName, tblScheduling.ScheduleID
FROM tblScheduling RIGHT OUTER JOIN
tblEntities ON tblScheduling.EntityID = tblEntities.EntityID
WHERE (tblScheduling.SchedulingYearID = #SchedulingYearID OR
tblScheduling.SchedulingYearID IS NULL)
AND (tblEntities.Active = 1)
ORDER BY tblEntities.EntityID;