Left Join gives no result - sql

These are the two tables.
tbl_Invoice
tbl_Payment
What I want is Pending Invoices by a particular Client.
Existing Query is as below:
Select * from tbl_Invoice I
left join tbl_payment P on I.client_id = P.client_id
left join tbl_client C on I.client_id = C.client_id
where I.invoice_Id not in (P.invoice_Id)
and I.client_id = 8
But it gives blank result becuase the Payment table is blank.

You need to move condition from WHERE to ON :
Select * from tbl_Invoice I
left join tbl_payment P on (I.client_id = P.client_id
AND p.invoice_id <> I.invoice_Id)
left join tbl_client C on I.client_id = C.client_id
WHERE I.client_id = 5

Related

sql - how to sum a dynamically created column with the same id?

select
Cu.CustomerNum, Cu.Name, sum(Cio1.Quantity * C1.Price) AS Total_Income
from
Orders O1
inner join
CoursesInOrder Cio1 on O1.OrderNum = Cio1.OrderNum
inner join
Customer Cu on Cu.CustomerNum = O1.CustomerNum
inner join
Course C1 on C1.CourseNum = Cio1.CourseNum
where
O1.CustomerNum in (select O.CustomerNum
from Course C
inner join CoursesInOrder Cio on C.CourseNum = Cio.CourseNum
inner join Orders O on O.OrderNum= Cio.OrderNum
where C.CourseNum = '99771'
and year(O.Shiftdate) = '2014'
group by O.CustomerNum
having count(O.CustomerNum) > 2)
[Current output]
[Wanted output]
I'm trying to sum the dynamically created solumn - Total_Income,
it keeps giving me almost-random errors,
would appreciate any help!
select
Cu.CustomerNum, Cu.Name, sum(Cio1.Quantity * C1.Price) AS Total_Income
from
Orders O1
inner join
CoursesInOrder Cio1 on O1.OrderNum = Cio1.OrderNum
inner join
Customer Cu on Cu.CustomerNum = O1.CustomerNum
inner join
Course C1 on C1.CourseNum = Cio1.CourseNum
where
O1.CustomerNum in (select O.CustomerNum
from Course C
inner join CoursesInOrder Cio on C.CourseNum = Cio.CourseNum
inner join Orders O on O.OrderNum= Cio.OrderNum
where C.CourseNum = '99771'
and year(O.Shiftdate) = '2014'
group by O.CustomerNum
having count(O.CustomerNum) > 2)
Group by Cu.CustomerNum, Cu.Name

Oracle SQL How to Count Column Value Occurences and Group BY during joins

I'm working on another SQL query, trying to group a collection of records while doing a count and joining tables. See below for goal, current query, and attached scripts for building and populating tables.
Show all customers who have checked more books than DVDs. Display
customer name, total book checkouts and total DVD checkouts. Sort
results by customer first name and last name.
SELECT C.CUSTOMER_FIRSTNAME, C.CUSTOMER_LASTNAME, COUNT(T.TRANSACTION_ID)
FROM customer C
INNER JOIN library_card LC ON C.CUSTOMER_ID = LC.CUSTOMER_ID
INNER JOIN transaction T ON LC.LIBRARY_CARD_ID = T.LIBRARY_CARD_ID
INNER JOIN physical_item P ON T.PHYSICAL_ITEM_ID = P.PHYSICAL_ITEM_ID
INNER JOIN catalog_item CT ON P.CATALOG_ITEM_ID = CT.CATALOG_ITEM_ID
GROUP BY C.CUSTOMER_FIRSTNAME, C.CUSTOMER_LASTNAME
ORDER BY C.CUSTOMER_FIRSTNAME, C.CUSTOMER_LASTNAME;
Run first: https://drive.google.com/open?id=1PYAZV4KIfZtxP4eQn35zsczySsxDM7ls
Run second: https://drive.google.com/open?id=1pAzWmJqvD3o3n6YJqVUM6TtxDafKGd3f
EDIT
With some help from Mr. Barbaros I've come up with the below query, which is closer. However, this query isn't returning any results for DVDs, which leads me to believe it's a join issue.
SELECT C.CUSTOMER_FIRSTNAME, C.CUSTOMER_LASTNAME, COUNT(CT1.TYPE) AS BOOK_COUNT, COUNT(CT2.TYPE) AS DVD_COUNT
FROM customer C
INNER JOIN library_card LC ON C.CUSTOMER_ID = LC.CUSTOMER_ID
INNER JOIN transaction T ON LC.LIBRARY_CARD_ID = T.LIBRARY_CARD_ID
INNER JOIN physical_item P ON T.PHYSICAL_ITEM_ID = P.PHYSICAL_ITEM_ID
INNER JOIN catalog_item CT1 ON P.CATALOG_ITEM_ID = CT1.CATALOG_ITEM_ID AND CT1.TYPE = 'BOOK'
LEFT OUTER JOIN catalog_item CT2 ON P.CATALOG_ITEM_ID = CT2.CATALOG_ITEM_ID AND CT2.TYPE = 'DVD'
GROUP BY C.CUSTOMER_FIRSTNAME, C.CUSTOMER_LASTNAME, CT1.TYPE, CT2.TYPE
ORDER BY C.CUSTOMER_FIRSTNAME, C.CUSTOMER_LASTNAME;
Use "conditional aggregates" (use a case expression inside the aggregate function)
SELECT
C.CUSTOMER_FIRSTNAME
, C.CUSTOMER_LASTNAME
, COUNT( CASE WHEN CT.TYPE = 'BOOK' THEN T.TRANSACTION_ID END ) books
, COUNT( CASE WHEN CT.TYPE = 'DVD' THEN T.TRANSACTION_ID END ) dvds
FROM customer C
INNER JOIN library_card LC ON C.CUSTOMER_ID = LC.CUSTOMER_ID
INNER JOIN transaction T ON LC.LIBRARY_CARD_ID = T.LIBRARY_CARD_ID
INNER JOIN physical_item P ON T.PHYSICAL_ITEM_ID = P.PHYSICAL_ITEM_ID
INNER JOIN catalog_item CT ON P.CATALOG_ITEM_ID = CT.CATALOG_ITEM_ID
GROUP BY
C.CUSTOMER_FIRSTNAME
, C.CUSTOMER_LASTNAME
HAVING
COUNT( CASE WHEN CT.TYPE = 'BOOK' THEN T.TRANSACTION_ID END )
> COUNT( CASE WHEN CT.TYPE = 'DVD' THEN T.TRANSACTION_ID END )
ORDER BY
C.CUSTOMER_FIRSTNAME
, C.CUSTOMER_LASTNAME
;
You can use catalog_item table twice( think of as seperate tables for books and dvds ), and compare by HAVING clause as :
SELECT C.CUSTOMER_FIRSTNAME, C.CUSTOMER_LASTNAME,
COUNT(CT1.CATALOG_ITEM_ID) as "Book Checkout",
COUNT(CT2.CATALOG_ITEM_ID) as "DVD Checkout"
FROM customer C
INNER JOIN library_card LC ON C.CUSTOMER_ID = LC.CUSTOMER_ID
INNER JOIN transaction T ON LC.LIBRARY_CARD_ID = T.LIBRARY_CARD_ID
INNER JOIN physical_item P ON T.PHYSICAL_ITEM_ID = P.PHYSICAL_ITEM_ID
LEFT JOIN catalog_item CT1 ON P.CATALOG_ITEM_ID = CT1.CATALOG_ITEM_ID AND CT1.TYPE = 'BOOK'
LEFT JOIN catalog_item CT2 ON P.CATALOG_ITEM_ID = CT2.CATALOG_ITEM_ID AND CT1.TYPE = 'DVD'
GROUP BY C.CUSTOMER_FIRSTNAME, C.CUSTOMER_LASTNAME
HAVING COUNT(CT1.CATALOG_ITEM_ID) > COUNT(CT2.CATALOG_ITEM_ID)
ORDER BY C.CUSTOMER_FIRSTNAME, C.CUSTOMER_LASTNAME;
CUSTOMER_FIRSTNAME CUSTOMER_LASTNAME Book Checkout DVD Checkout
------------------ ----------------- ------------- -------------
Deena Pilgrim 3 1
Emile Cross 5 2
Please try to remove ,CT1.TYPE, CT2.TYPE on your group by clause.

Nested query WHERE procedure code IN and AND

Would like to take the following Query and alter it so that it brings back ONLY records where each patient (based on MRN) has BOTH ProcedureCodeList IN ('115-1','117-1','311-1') AND ProcedureCodeList = '119-103'
SELECT P.SiteID, O.ProcedureCodeList, P.MRN, PINFO.LastName, PINFO.FirstName, PINFO.[State] AS Species, PINFO.City AS Breed, O.ProcedureDescList, RF.FieldName, RF.FieldValue, R.ContentText
, R.LastSignDate
FROM ReportFinding RF
INNER JOIN Report R
ON RF.ReportID = R.ReportID
INNER JOIN [Order] O
ON R.ReportID = O.ReportID
INNER JOIN Visit V
ON O.VisitID = V.VisitID
INNER JOIN Patient P
ON P.PatientID = V.PatientID
INNER JOIN PersonalInfo PINFO
ON P.PersonalInfoID = PINFO.PersonalInfoID
WHERE
O.ProcedureCodeList IN ('115-1','117-1','119-103')
ORDER BY R.LastSignDate DESC
There are a couple of ways to solve this. One way is to create two subqueries and join them on the MRN.
SELECT a.SiteID, a.ProcedureCodeList, a.MRN, a.LastName, a.FirstName, a.Species, a.Breed, a.ProcedureDescList, a.FieldName, a.FieldValue, a.ContentText, a.LastSignDate
FROM
(SELECT P.SiteID, O.ProcedureCodeList, P.MRN, PINFO.LastName, PINFO.FirstName, PINFO.[State] AS Species, PINFO.City AS Breed, O.ProcedureDescList, RF.FieldName, RF.FieldValue, R.ContentText, R.LastSignDate
FROM ReportFinding RF
INNER JOIN Report R ON RF.ReportID = R.ReportID
INNER JOIN [Order] O ON R.ReportID = O.ReportID
INNER JOIN Visit V ON O.VisitID = V.VisitID
INNER JOIN Patient P ON P.PatientID = V.PatientID
INNER JOIN PersonalInfo PINFO ON P.PersonalInfoID = PINFO.PersonalInfoID
WHERE O.ProcedureCodeList IN ('115-1','117-1','119-103')) as a
JOIN
(SELECT P.MRN
FROM [Order]
INNER JOIN Visit V ON O.VisitID = V.VisitID
INNER JOIN Patient P ON P.PatientID = V.PatientID
WHERE O.ProcedureCodeList = '119-103') as b ON a.MRN = b.MRN
ORDER BY a.LastSignDate
The PersonalInfo table is not needed in the second query. I don't think ReportFinding and Report are either, based on your JOINs. It depends on what these tables are actually doing.
Another way starts with the original query and adds the following to the WHERE clause (before the ORDER BY):
AND P.MRN IN
(SELECT P.MRN
FROM [Order]
INNER JOIN Visit V ON O.VisitID = V.VisitID
INNER JOIN Patient P ON P.PatientID = V.PatientID
WHERE O.ProcedureCodeList = '119-103')
I would look at the execution plans of both solutions to know which is the better one in this case.

Too many results in query

I'm fetching some data from our database in MSSQL. Out of this data I want to determine who created the client entry and who took the first payment from this client.
There can be many payment entries for a client on a single booking/enquiry and at the moment, my query shows results for each payment. How can I limit the output to only show the first payment entry?
My query:
SELECT
c.FirstName,
c.LastName,
c.PostalCode,
o.OriginOfEnquiry,
s.SuperOriginName,
c.DateOfCreation,
DATEDIFF(day, c.DateOfCreation, p.DateOfCreation) AS DaysToPayment,
pc.PackageName,
CONCAT(u.FirstName, ' ', u.LastName) AS CreateUser,
(SELECT CONCAT(u.FirstName, ' ', u.LastName)
WHERE u.UserID = p.UserID ) AS PaymentUser
FROM tblBookings b
INNER JOIN tblPayments p
ON b.BookingID = p.BookingID
INNER JOIN tblEnquiries e
ON e.EnquiryID = b.EnquiryID
INNER JOIN tblCustomers c
ON c.CustomerID = e.CustomerID
INNER JOIN tblOrigins o
ON o.OriginID = e.OriginID
INNER JOIN tblSuperOrigins s
ON s.SuperOriginID = o.SuperOriginID
INNER JOIN tblBookingPackages bp
ON bp.bookingID = p.BookingID
INNER JOIN tblPackages pc
ON pc.PackageID = bp.packageID
INNER JOIN tblUsers u
ON u.UserID = c.UserID
WHERE c.DateOfCreation >= '2016-06-01' AND c.DateOfCreation < '2016-06-30'
AND p.PaymentStatusID IN (1,2)
AND e.CustomerID = c.CustomerID
AND p.DeleteMark != 1
AND c.DeleteMark != 1
AND b.DeleteMark != 1
;
I tried adding a "TOP 1" to the nested select statement for PaymentUser, but it made no difference.
you can use cross apply with top 1:
FROM tblBookings b
cross apply
(select top 1 * from tblPayments p where b.BookingID = p.BookingID) as p
Instead of table tblPayments specify sub-query like this:
(SELECT TOP 1 BookingID, UserID, DateOfCreation
FROM tblPayments
WHERE DeleteMark != 1
AND PaymentStatusID IN (1,2)
ORDER BY DateOfCreation) as p
I'm assuming that tblPayments has a primary key column ID. If it is true, you can use this statment:
FROM tblBookings b
INNER JOIN tblPayments p ON p.ID = (
SELECT TOP 1 ID
FROM tblPayments
WHERE BookingID = b.BookingID
AND DeleteMark != 1
AND PaymentStatusID IN (1,2)
ORDER BY DateOfCreation)

SQL use nested select in middle of inner join

Is it possible to use a select in the middle of joining...
I am trying to do the following:
FROM
tblorders o
INNER JOIN tblunits u on o.id = u.orderid
INNER JOIN ((SELECT
,Min(n.date) as [MinDate]
from tblNotes n
Where n.test = 'test') te
INNER JOIN tblnotes n on te.id = n.id
and te.[MinDate] = n.AuditinsertTimestamp)
INNER Join tblClient c ON o.ClientId = c.Id
Basically in the select in the middle of the query it is selecting only the notes with min date. The problem is I need to do this here because I need from tblOrders to be the first table.......
Suggestions?
The INNER JOIN failed because you have a leading comma here:
,Min(n.date) as [MinDate]
I think you are looking for something like this:
SELECT ...
FROM tblorders o
INNER JOIN tblunits u on o.id = u.orderid
INNER JOIN (
SELECT id, Min(date) as [MinDate]
from tblNotes
Where test = 'test'
group by id
) te <-- not sure what JOIN clause to use here, please post schema
INNER JOIN tblnotes n on te.id = n.id
and te.[MinDate] = n.AuditinsertTimestamp
INNER Join tblClient c ON o.ClientId = c.Id
You are missing an alias and join condition:
FROM
tblorders o
INNER JOIN tblunits u on o.id = u.orderid
INNER JOIN ((SELECT Min(n.date) as [MinDate]
from tblNotes n
Where n.test = 'test') te
INNER JOIN tblnotes n on te.id = n.id
and te.[MinDate] = n.AuditinsertTimestamp)
-- missing
AS z
ON <join conditions haere>
INNER Join tblClient c ON o.ClientId = c.Id
Yes, you can have a Select in a Join.