Perform right outer join with a condition for left table - sql

I have two tables,
Student:
rollno | name
1 | Abc
2 | efg
3 | hij
4 | klm
Attendance:
name | date |status
Abc | 10-10-2013 | A
efg | 10-10-2013 | A
Abc | 11-10-2013 | A
hij | 25-10-2013 | A
My required output is:
Some query with where condition as "where date between '10-09-2013' and '13-10-2013' "
rollno| name |count
1 | Abc | 2
2 | efg | 1
3 | hij | 0
4 | klm | 0
I tried using:
SELECT p.rollno,p.name,case when s.statuss='A' then COUNT(p.rollno) else '0' end as count
from attendance s
right outer join student p
on s.rollno=p.rollno
where s.date between '10-09-2013' and '13-10-2013'
group by p.rollno,p.regno,p.name,s.statuss
order by p.rollno
And the Output is:
rollno| name |count
1 | Abc | 2
2 | efg | 1
I want the remaining values from the student table to also be appended. I have tried many different queries, but all have been unsuccessful. Is there a query that will return the required output above?

You need to move the criteria from the where to the join:
SELECT p.rollno,p.name,case when s.statuss='A' then COUNT(p.rollno) else 0 end as count
from attendance s
right outer join student p
on s.rollno=p.rollno
and s.date between '10-09-2013' and '13-10-2013'
group by p.rollno,p.regno,p.name,s.statuss
order by p.rollno;
At the moment even though you have an outer join, by referring to the outer table in the where clause you effectively turn it into an inner join. Where there is no match in attendance, s.Date will be NULL, and because NULL is not between '10-09-2013' and '13-10-2013' the rows are excluded.
It is not apparent from the question, but I would image that what you are actually looking for is this. It appears you are just after a count of entries in attendance where status = 'A' by student:
SELECT p.rollno,
p.name,
COUNT(s.statuss) as count
from attendance s
right outer join student p
on s.rollno=p.rollno
and s.date between '10-09-2013' and '13-10-2013'
AND s.statuss = 'A'
group by p.rollno,p.regno,p.name,
order by p.rollno;
I have removed s.statuss from the group by, and changed the count so that there is only one row per student, rather than one row per status per student. I have changed the column within the count to a column in the attendance status table, to ensure that you get a count of 0 when there are no entries in attendance. if you use a column in students you will get a count of 1 even when there are no entries. Finally, since you are only interested in entries with statuss = 'A' I have also moved this to the join condition.
On one final note, it is advisable when using strings for dates to use the culture insensitive format yyyyMMdd, as this is completely unanbiguous, 20130201' is always the 1st February, and never 2nd January, whereas in your query10-09-2013' could be 10th September, or 9th October, depending on your settings.

Related

How can I group by this query that there's not two columns per entry

I have this query in flexible search:
SELECT
{p.pk} AS PK,
{year.code} AS year
FROM {Product AS p
LEFT JOIN Year AS y ON {p.yearpk}={year.pk}
}
ORDER BY {p.pk} ASC
As result I get:
PK | year
---------------
1 | null
1 | 2016
2 | null
2 | 2016
How can I group by these multiple records into one like:
PK | year
---------------
1 | 2016
2 | 2016
I've already tried with "GROUP BY {p.pk}" but then the query doesn't returns me the result I've mentioned above - instead it returns 2 records but the year is null instead of 2016.
How can I solve this?
You need to change your left join to an inner join. That should solve your issue.

SQL 2 Left outer joins with Sum and Group By

Looking for some guidance on this. I am attempting to run a report in my complaint management system.. Complaints by Year, Location, Subcategory, Showing Totals for TotalCredits (child table) and TotalsCwts (childtable) as well as total ExternalRootCause (on master table).
This is my SQL, but the TotalCwts and TotalCredits are not being calculated correctly. It calculates 1 time for each child record rather than the total for each master record.
SELECT
dbo.Complaints.Location,
YEAR(dbo.Complaints.ComDate) AS Year,
dbo.Complaints.ComplaintSubcategory,
COUNT(Distinct(dbo.Complaints.ComId)) AS CustomerComplaints,
SUM(DISTINCT CASE WHEN (dbo.Complaints.RootCauseSource = 'External' ) THEN 1 ELSE 0 END) as ExternalRootCause,
SUM(dbo.ComplaintProducts.Cwts) AS TotalCwts,
Coalesce(SUM(dbo.CreditDeductions.CreditAmount),0) AS TotalCredits
FROM dbo.Complaints
JOIN dbo.CustomerComplaints
ON dbo.Complaints.ComId = dbo.CustomerComplaints.ComId
LEFT OUTER JOIN dbo.CreditDeductions
ON dbo.Complaints.ComId = dbo.CreditDeductions.ComId
LEFT OUTER JOIN dbo.ComplaintProducts
ON dbo.Complaints.ComId = dbo.ComplaintProducts.ComId
WHERE
dbo.Complaints.Location = Coalesce(#Location,Location)
GROUP BY
YEAR(dbo.Complaints.ComDate),
dbo.Complaints.Location,
dbo.Complaints.ComplaintSubcategory
ORDER BY
[YEAR] desc,
dbo.Complaints.Location,
dbo.Complaints.ComplaintSubcategory
Data Results
Location | Year | Subcategory | Complaints | External RC | Total Cwts | Total Credits
---------------------------------------------------------------------------------------
Boston | 2016 | Documentation | 1 | 0 | 8 | 8.00
Data Should Read
Location | Year | Subcategory | Complaints | External RC | Total Cwts | Total Credits
---------------------------------------------------------------------------------------
Boston | 2016 | Documentation | 1 | 0 | 4 | 2.00
Above data reflects 1 complaint having 4 Product Records with 1cwt each and 2 credit records with 1.00 each.
What do I need to change in my query or should I approach this query a different way?
The problem is that the 1 complaint has 2 Deductions and 4 products. When you join in this manner then it will return every combination of Deduction/Product for the complaint which gives 8 rows as you're seeing.
One solution, which should work here, is to not query the Dedustion and Product tables directly; query a query which returns one row per table per complaint. In other words, replace:
LEFT OUTER JOIN dbo.CreditDeductions ON dbo.Complaints.ComId = dbo.CreditDeductions.ComId
LEFT OUTER JOIN dbo.ComplaintProducts ON dbo.Complaints.ComId = dbo.ComplaintProducts.ComId
...with this - showing the Deductions table only, you can work out the Products:
LEFT OUTER JOIN (
select ComId, count(*) CountDeductions, sum(CreditAmount) CreditAmount
from dbo.CreditDeductions
group by ComId
) d on d.ComId = Complaints.ComId
You'll have to change the references to dbo.CreditDedustions to just d (or whatever you want to call it).
Once you've done them both then you'll one each per complaint, which will result with 1 row per complaint contaoining the counts and totals from the two sub-tables.

INNER JOIN Need to use column value twice in results

I've put in the requisite 2+ hours of digging and not getting an answer.
I'd like to merge 3 SQL tables, where Table A and B share a column in common, and Table B and C share a column in common--Tables A and C do not.
For example:
Table A - entity_list
entity_id | entity_name | Other, irrelevant columns
Example:
1 | Microsoft |
2 | Google |
Table B - transaction_history
transaction_id | purchasing_entity | supplying_entity | other, irrelevant columns
Example:
1 | 2 | 1
Table C - transaction_details
transactional_id | amount_of_purchase | Other, irrelevant columns
1 | 5000000 |
Using INNER JOIN, I've been able to get a result where I can link entity_name to either purchasing_entity or supplying_entity. And then, in the results, rather than seeing the entity_id, I get the entity name. But I want to substitute the entity name for both purchasing and supplying entity.
My ideal results would look like this:
1 [transaction ID] | Microsoft | Google | 5000000
The closes I've come is:
1 [transaction ID] | Microsoft | 2 [Supplying Entity] | 5000000
To get there, I've done:
SELECT transaction_history.transaction_id,
entity_list.entity_name,
transaction_history.supplying_entity,
transaction_details.amount_of_purchase
FROM transaction.history
INNER JOIN entity_list
ON transaction_history.purchasing_entity=entity_list.entity.id
INNER JOIN
ON transaction_history.transaction_id=transaction_details.transaction_id
I can't get entity_name to feed to both purchasing_entity and supplying_entity.
Here is the query:
SELECT h.transaction_id, h.purchasing_entity, purchaser.entity_name, h.supplying_entity, supplier.entity_name, d.amount_of_purchase
FROM transaction_history h
INNER JOIN transaction_details d
ON h.transaction_id = d.transaction_id
INNER JOIN entity_list purchaser
ON h.purchasing_entity = purchaser.entity_id
INNER JOIN entity_list supplier
ON h.supplying_entity = supplier.entity_id

GROUP BY shows the same group more than once when using CASE

I'm having an issue with a CASE Statement in T-SQL
Here is the query:
Select
CASE WHEN cri.ChartRetrievalMethodID IS NULL THEN wfseg.SiteEventGroupID
ELSE cri.ChartRetrievalMethodID END as Type,
count(distinct c.chartid) TotalCharts
From Sites s LEFT JOIN Charts c ON s.SiteID=c.SiteID
LEFT JOIN ChartRetrievalInformation cri ON c.ChartID=cri.ChartID
LEFT JOIN WFSiteEvents wfse ON wfse.SiteID=s.siteid
LEFT JOIN WFSiteEventTypes wfset ON wfset.EventTypeID=wfse.EventTypeID
LEFT JOIN WFSiteEventGroups wfseg ON wfset.SiteEventGroupID=wfseg.SiteEventGroupID
Where
wfse.EventStatusID in (1,2)
and s.ProjectID=110
group by
cri.ChartRetrievalMethodID, wfseg.SiteEventGroupID
I'm getting a lot of multiple rows instead of them combining into one - example:
+------+--------------+
| Type | Total Charts |
+------+--------------+
| 3 | 28 |
| 3 | 3 |
+------+--------------+
Ideally I would like these two rows mashed together to be just one:
+------+--------------+
| Type | Total Charts |
+------+--------------+
| 3 | 31 |
+------+--------------+
I'm sure there is nothing I'm writing incorrectly but I can't seem to see what it is.
If you include the fields cri.ChartRetrievalMethodID, wfseg.SiteEventGroupID in the column list for your select statement, it will become clear to you why these are shown in multiple rows with that grouping.
What you want to do is group by the value you're calling Type. In another DBMS this would be as simple as GROUP BY Type, but in SQL Server you must repeat the full expression in the GROUP BY clause.

My SQL query within a query

I have 2 tables that I am trying to combine in a specific way
Table 1: ‘part_defs’ Table 2 Items_part_values
in value_defs:
ID | Name
-------------
1 | color
2 | size
3 | weight
in Items_part_values
ItemID | valueID | Value
-------------------------
10 | 1 | red
11 | 1 | blue
What I need is a query where for a given item all the rows from value_defs appear and if they have a value in Items_part_values the value.
So for Item 11 I want
ID | Name | Value
--------------------
1 | color | red
2 | size | NULL
3 | weight | NULL
I’m new to MySQL, in access I would have created a subquery with the ItemID as a parameter and then done a Left Join with value_defs on the result.
Is there a way of doing something similar in MySQL?
Thanks
Use:
SELECT p.id,
p.name,
ipv.value
FROM PART_DEFS p
LEFT JOIN ITEMS_PART_VALUES ipv ON ipv.valueid = p.id
AND ipv.itemid = ?
Replace the "?" with the itemid you want to search for.
This means all the PARTS_DEF rows will be returned, and if the ITEMS_PART_VALUES.valueid matches the PART_DEFS.id value, then the ITEMS_PART_VALUES.value value will be displayed for the item you are looking for. If there's no match, the value column will be NULL for that record.
There's a difference in OUTER JOINs, when specifying criteria in the JOIN vs the WHERE clause. In the JOIN, the criteria is applied before the JOIN occurs while in the WHERE clause the criteria is applied after the JOIN.
Use a left join:
SELECT * FROM Table1 LEFT JOIN Table2 USING (ID);
Edit:
SELECT * FROM part_defs LEFT JOIN Items_part_values ON part_defs.ID = Items_part_values.valueID;