Proper JOIN for Adding a 4th Table to a Query - sql

Asked a similar question HERE but this extends it.
Here's the original query:
SELECT p.pid
, p.title
, p.description
, p.price
, p.datecreated AS pdate
, p.image1
, c.cid
, c.comment
, c.datecreated AS cdate
, pa.fname AS PFName
, pa.lname AS PLName
, ca.fname AS CFName
, ca.lname AS CLName
FROM tblPosts p
LEFT JOIN tblUsers pa ON pa.uid = p.uid
LEFT JOIN tblComments c ON p.pid = c.pid
LEFT JOIN tblUsers ca ON ca.uid = c.uid
ORDER BY p.pid
I need to add a fourth table (tblPostStatus) that holds the status of each post(statusType) which can be one of 2 different values. When I try to add the JOIN I seem to get duped rows, one for each row in tblPostStatus (there are 3 records in this table). This table has fields sid, pid, uid, statusType.
New Query:
SELECT p.pid
, p.title
, p.description
, p.price
, p.datecreated AS pdate
, p.image1
, c.cid
, c.comment
, c.datecreated AS cdate
, pa.fname AS PFName
, pa.lname AS PLName
, ca.fname AS CFName
, ca.lname AS CLName
, ps.statusType
FROM tblPosts p
LEFT JOIN tblUsers pa ON pa.uid = p.uid
LEFT JOIN tblComments c ON p.pid = c.pid
LEFT JOIN tblUsers ca ON ca.uid = c.uid
LEFT JOIN tblPostStatus ps ON p.pid = ps.pid
ORDER BY p.pid
See query result pics:
Do these results look proper or am I doing something incorrectly?

(Summary from chat)
The overall requirements changed a bit. Ultimately "Status" is related to a post, user and comment record, so status was moved to the comment table. An additional requirement was added: identify posts with "claim" comments.
SQL Fiddle
SELECT p.pid
, p.title
, c.cid
, c.comment
, c.statusType
, COALESCE(cnt.HasClaim, 0) AS HasClaim
, pa.fname AS PFName
, pa.lname AS PLName
, ca.fname AS CFName
, ca.lname AS CLName
FROM tblPosts p
LEFT JOIN tblUsers pa ON pa.uid = p.uid
LEFT JOIN tblComments c ON p.pid = c.pid
LEFT JOIN tblUsers ca ON ca.uid = c.uid
LEFT JOIN (
SELECT pid, COUNT(*) AS HasClaim
FROM tblComments
WHERE statusType = 1
GROUP BY pid
) cnt ON cnt.pid = p.pid
ORDER BY p.pid, c.cid

Related

How to show the last value of the another table column based on the between date

I have 4 tables:
INVOICE, contains the entry date
INVOICE_ITEM contains the product cod's
PRODUCTS, here contains the STANDARD column, if i use the Nvl(P.STANDARD, 'Y'). It shows only the actual date value.
PRODUCT_HIST (contains all the updates of the products table)
I'm trying to select the "standard" value of the product_hist based on the invoice entry date.
Here is my select, it works but doesnt show the correct value
SELECT NT.INVOICE
, NT.PROVIDER
, NT.ENTRY
, NTI.PRODUCT
, P.COD
, P.NAME
, Nvl(P.STANDARD, 'Y') "STANDARD_ACTUAL"
, COALESCE (PRODUCT_HIST.STANDARD, P.PRODUCT, 'Y') "STANDARD2"
FROM INVOICE NT
INNER JOIN INVOICE_ITEM NTI ON NT.NOTE = NTI.NOTE AND NT.PROVIDER = NTI.PROVIDER
INNER JOIN PRODUCTS P ON P.COD = NTI.PRODUCT
LEFT JOIN (SELECT PH.COD COD
, Nvl(PH.STANDARD, Last_Value(PH.STANDARD IGNORE NULLS) OVER (PARTITION BY PH.COD ORDER BY PH.DATE ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING)) STANDARD
, DATE
, Nvl(Lag(PH.DATE) OVER (PARTITION BY PH.COD ORDER BY PH.DATE DESC), SYSDATE) FINALDATE
, Row_Number() OVER (PARTITION BY COD ORDER BY COD, DATE, STANDARD DESC) ORDER
FROM PRODUCT_HIST PH) PRODUCT_HIST ON PRODUCT_HIST.COD = P.COD AND NT.ENTRY BETWEEN PRODUCT_HIST.DATE AND PRODUCT_HIST.FINALDATE AND PRODUCT_HIST.ORDER = 1
WHERE NT.ENTRY BETWEEN TO_DATE('01/01/2019','DD/MM/YYYY') AND TO_DATE('31/12/2019','DD/MM/YYYY')+0.99999
I need to show the last value of the "standard" between the entry invoice date, sometimes it will be null, so i have to use NVL or COALESCE.
Can someone help me on this?
I would post this as a comment, but unformatted SQL statements are unreadable.
What is the issue with something like;
SELECT NT.INVOICE
, NT.PROVIDER
, NT.ENTRY
, NTI.PRODUCT
, P.COD
, P.NAME
, Nvl(P.STANDARD, 'Y') "STANDARD_ACTUAL"
, COALESCE ((SELECT MAX(PH.STANDARD) FROM PRODUCT_HIST PH WHERE PH.COD = P.COD AND NT.ENTRY BETWEEN PRODUCT_HIST.DATE AND PRODUCT_HIST.FINALDATE AND PRODUCT_HIST.ORDER = 1),
P.PRODUCT, 'Y') "STANDARD2"
FROM INVOICE NT
INNER JOIN INVOICE_ITEM NTI ON NT.NOTE = NTI.NOTE AND NT.PROVIDER = NTI.PROVIDER
INNER JOIN PRODUCTS P ON P.COD = NTI.PRODUCT
LEFT OUTER JOIN PRODUCT_HIST PH ON PH.COD = P.COD AND
WHERE NT.ENTRY BETWEEN TO_DATE('01/01/2019','DD/MM/YYYY') AND TO_DATE('31/12/2019','DD/MM/YYYY')+0.99999
Let me know how I missed the mark if it isn't close.
OK, this is a bit more convoluted, but it may work;
SELECT NT.INVOICE
, NT.PROVIDER
, NT.ENTRY
, NTI.PRODUCT
, P.COD
, P.NAME
, Nvl(P.STANDARD, 'Y') "STANDARD_ACTUAL"
, COALESCE ((SELECT PH.STANDARD
FROM PRODUCT_HIST PH
WHERE PH.COD = P.COD AND
NT.ENTRY BETWEEN PH.DATE AND
PH.FINALDATE AND
PH.ORDER = 1 AND
PH.DATE = (SELECT MAX(PH1.DATE)
FROM PRODUCT_HIST PH1
WHERE PH1.COD = P.COD AND
NT.ENTRY BETWEEN PH1.DATE AND
PH1.FINALDATE AND
PH1.ORDER = 1) AND
ROWNUM = 1)
),
P.PRODUCT, 'Y') "STANDARD2"
FROM INVOICE NT
INNER JOIN INVOICE_ITEM NTI ON NT.NOTE = NTI.NOTE AND NT.PROVIDER = NTI.PROVIDER
INNER JOIN PRODUCTS P ON P.COD = NTI.PRODUCT
LEFT OUTER JOIN PRODUCT_HIST PH ON PH.COD = P.COD AND
WHERE NT.ENTRY BETWEEN TO_DATE('01/01/2019','DD/MM/YYYY') AND TO_DATE('31/12/2019','DD/MM/YYYY')+0.99999

Join SQL query not giving desired result

I have separate queries with me as follows:
SELECT c.id
FROM claim c,
company co,
customer cu
WHERE c.company_id = co.id
AND c.customer_id = cu.id
AND co.company_code = 'LTO'
AND cu.customer_no = '021540'
AND c.invoice_number IS NOT NULL
AND c.invoice_date IS NULL
AND c.invoice_number = '20170331'
SELECT Sum(price)
FROM replaced_part
WHERE claim_id IN ( 628099, 674047, 1182523, 1282549,
1479834, 1480585, 1487452, 1515238 );
SELECT Sum(price)
FROM allowance
WHERE claim_id IN ( 628099, 674047, 1182523, 1282549,
1479834, 1480585, 1487452, 1515238 );
I was trying to group together all the above queries into one using sql equi join as follows:
select co.company_Code,
cu.customer_No,
c.invoice_Number,
sum(r.price),
sum(a.price)
FROM claim c INNER JOIN company co ON c.COMPANY_ID=co.ID
INNER JOIN customer cu ON c.CUSTOMER_ID=cu.ID
INNER JOIN replaced_part r ON r.claim_id=c.id
INNER JOIN allowance a ON a.claim_id = c.id
WHERE co.company_code = 'LTO' and cu.customer_no='021540' and
c.INVOICE_NUMBER is not null and c.INVOICE_DATE is null and
c.INVOICE_NUMBER='20170331'
GROUP BY co.company_Code, cu.customer_No, c.invoice_Number
But I am not getting the desired result(Query execute successfully but the sum is incorrect) as I am getting after running the 3 separate queries defined above... What is the problem here in my query created using equi join??
Relationship between tables are claim ->(one to one) -> company ->(one to one) -> customer ->(one to many) ->Replaced_Part ->(one to many) -> allowance
Please try to use left join for Replaced_Part and allowance
select co.company_Code
, cu.customer_No
, c.invoice_Number
, (SELECT sum(r.price) FROM replaced_part r WHERE r.claim_id = c.id)
, (SELECT sum(a.price) FROM allowance a WHERE a.claim_id = c.id)
FROM claim c
INNER JOIN company co
ON c.COMPANY_ID=co.ID
INNER JOIN customer cu
ON c.CUSTOMER_ID=cu.ID
WHERE co.company_code = 'LTO'
AND cu.customer_no='021540'
AND c.INVOICE_DATE is null
AND c.INVOICE_NUMBER='20170331'
GROUP BY co.company_Code
, cu.customer_No
, c.invoice_Number
try to use temporary table, combine all the tables and make a temporary table, then fire your conditions on that table.
Example :
select co.company_Code,
cu.customer_No,
c.invoice_Number,
sum(r.price),
sum(a.price)
into #temp from (claim c
INNER JOIN company co ON c.COMPANY_ID=co.ID
INNER JOIN customer cu ON c.CUSTOMER_ID=cu.ID
INNER JOIN replaced_part r ON r.claim_id=c.id
INNER JOIN allowance a ON a.claim_id = c.id
and then use your conditions on #temp. like
select * from #temp
WHERE company_code = 'LTO' and customer_no='021540' and
INVOICE_NUMBER is not null and INVOICE_DATE is null and
INVOICE_NUMBER='20170331'
GROUP BY company_Code, customer_No, invoice_Number
Hope this will work for you.

Execute a query foreach row from a result set.

I have a query that needs to be executed for each row in a result set. I understand that I need to do this with cursors, but I dont know how.
The first query contains customers with a specific condition, I need to retreive the Id:s from them.
The second query selects the latest activity from these customers.
Query 1
SELECT DISTINCT c.Name, c.Id
FROM Persons p
JOIN Customers c ON c.id = p.Customer_Id
WHERE C.State = 3 AND c.SalesPerson_Id ='A3160011-CAA6-E411-A83E-AC7BA1B90A6D' AND c.Id NOT IN
(
SELECT Distinct p.Customer_Id
FROM Activities a
JOIN Persons p
ON a.Person_Id = p.Id
WHERE a.[Type] IN (5,6) AND a.[Time] > getdate()-30 AND a.[Time] < getdate()
)
AND c.id NOT IN
(
SELECT
DISTINCT p.Customer_Id
FROM
Persons p
JOIN HtmlEmails he ON p.Id = he.UserId
JOIN ReportLog rl ON he.Id = rl.HtmlEmails_Id
WHERE rl.[Time] > getdate()-30 AND rl.[Time] < getdate())
Query 2
SELECT TOP 1 *
FROM(
SELECT TOP 1 c.Name AS 'CustomerName', c.Id AS 'CustomerId', a.[Time] AS 'LastActivity',(p.FirstName + ' ' + p.LastName) AS 'UserFullName' , 'Login' AS 'Type'
FROM Activities a
JOIN Persons p ON p.Id = a.Person_Id
JOIN Customers c ON p.Customer_Id = c.Id
WHERE a.[Type] IN (5,6) AND a.[Time] < getdate()-30
ORDER BY a.[Time] DESC
UNION
SELECT TOP 1 c.Name AS 'CustomerName', c.Id AS 'CustomerId', a.[Time] AS 'LastActivity',(p.FirstName + ' ' + p.LastName) AS 'UserFullName' , 'Email' AS 'Type'
FROM Activities a
JOIN HtmlEmails he ON a.TargetId = he.Id
JOIN ReportLog rl on he.Id = rl.HtmlEmails_Id
JOIN Persons p ON p.Id = a.Person_Id
JOIN Customers c ON p.Customer_Id = c.Id
WHERE a.[Time] < getdate()-30
ORDER BY a.[Time] DESC
)AS x
ORDER BY 'LastActivity' DESC
Thanks!

Proper Syntax for 3 table SELECT query

I've got 3 tables:
tblPosts
tblComments
tblUsers
I'm trying to get a listing of Posts along with associated Comments. The tricky part seems to be getting the Posts and Comments to show the proper author (User). This is the closest I get but then the Posts authors are incorrect. I'm grouping my CFOutput on "pid", so I only get each post one time as I would expect.
SELECT tblPosts.pid
, tblPosts.title
, tblPosts.description
, tblPosts.price
, tblPosts.datecreated AS pdate
, tblPosts.image1
, tblComments.comment
, tblComments.datecreated AS cdate
, tblUsers.fname
, tblUsers.lname
FROM tblPosts
LEFT JOIN tblComments ON tblPosts.pid = tblComments.pid
LEFT JOIN tblUsers ON tblComments.uid = tblUsers.uid
Any thoughts?
Thanks!
Since both tables contain an author id, you must to JOIN to tblUser twice: once for posts and once for comments. That means you must use a table alias to differentiate between the two. Something along these lines, where pa is the alias for "Post Author" and ca the alias for "Comment Author".
SELECT p.pid
, p.title
, ...
, pa.fname AS PostAuthorFirstName
, pa.lname AS PostAuthorLastName
, ca.fname AS CommentAuthorFirstName
, ca.lname AS CommentAuthorLastName
FROM tblPosts p
LEFT JOIN tblUsers pa ON pa.uid = p.uid
LEFT JOIN tblComments c ON p.pid = c.pid
LEFT JOIN tblUsers ca ON ca.uid = c.uid
I'm not familiar with all the fields in you tables. Join the post to the users table as well to get the specific users for writing posts.
How about trying this:
SELECT p.pid
,p.title
,p.description
,p.price
,p.datecreated AS pdate
,p.image1
,c.comment
,c.datecreated AS cdate
,u1.fname AS CommentAuthorsName
,u1.lname AS CommentAuthorsLastName
,u2.fname AS PostAuthorName
,u2.lname AS PostAuthorLastName
FROM tblPosts p
LEFT JOIN tblComments c
ON p.pid = c.pid
LEFT JOIN tblUsers u1
ON c.uid = u1.uid
LEFT JOIN tblUsers u2
ON p.uid = u2.uid

Sql Server - 2 queries executed together takes longer

I have 2 queries.
Query # 1: inserts some data into a temp table
Query # 2: inserts the data from the temp table (with some joins) into a new table.
Running Query #1 alone takes 3 seconds. Running Query #2 alone takes 12 seconds.
When I run them both together as one execution, it runs forever (over 4 minutes).
What could possibly be the reason for this?
(I would post my code but it's very long and not much understandable to the outsider.)
Here's my SQL (at your own risk): Remember they run fine when ran alone.
-- START QUERY #1
SELECT * INTO #TempProdForSiteGoingTrim
FROM
(
SELECT
p.idProduct
, p.active
, p.sku
, p.description
, p.listprice
, p.price
, p.imageurl
, p.smallimageurl
, p.idManufacturer
, sortOrder
, CASE WHEN p.pgroup = '' OR p.pgroup IS NULL THEN CAST(p.idProduct AS VARCHAR) ELSE pgroup END [pgroup]
, CASE WHEN pa2.attr IS NULL THEN CAST(p.idProduct AS VARCHAR) ELSE CASE WHEN p.pgroup = '' OR p.pgroup IS NULL THEN CAST(p.idProduct AS VARCHAR) ELSE pgroup END END [RugGroup]
, pa1.attr [Color]
, pa3.attr [Collection]
, pa2.attr [RugSize]
, pa4.attr[RugShape]
FROM
(SELECT DISTINCT idProduct FROM ProdSite WHERE idSite = 39 ) s
INNER JOIN (SELECT * FROM products p WHERE active = -1 ) p ON s.idproduct = p.idproduct
LEFT OUTER JOIN (SELECT t.idproduct, attr FROM (SELECT max(idprodattr) [idprodattr], idproduct, b.idattrset FROM productattr a JOIN product_attr b on a.idattr = b.idattr WHERE idattrset = 1 GROUP BY a.idproduct, b.idattrset )t JOIN productattr a ON t.idprodattr = a.idprodattr JOIN product_attr b ON a.idattr = b.idattr) pa1 ON p.idproduct = pa1.idproduct
LEFT OUTER JOIN (SELECT t.idproduct, attr FROM (SELECT max(idprodattr)[idprodattr], idproduct, b.idattrset FROM productattr a JOIN product_attr b on a.idattr = b.idattr WHERE idattrset = 160 GROUP BY a.idproduct, b.idattrset )t JOIN productattr a ON t.idprodattr = a.idprodattr JOIN product_attr b ON a.idattr = b.idattr) pa2 ON p.idproduct = pa2.idproduct
LEFT OUTER JOIN (SELECT t.idproduct, attr FROM (SELECT max(idprodattr)[idprodattr], idproduct, b.idattrset FROM productattr a JOIN product_attr b on a.idattr = b.idattr WHERE idattrset = 6 GROUP BY a.idproduct, b.idattrset )t JOIN productattr a ON t.idprodattr = a.idprodattr JOIN product_attr b ON a.idattr = b.idattr) pa3 ON p.idproduct = pa3.idproduct
LEFT OUTER JOIN (SELECT t.idproduct, attr FROM (SELECT max(idprodattr)[idprodattr], idproduct, b.idattrset FROM productattr a JOIN product_attr b on a.idattr = b.idattr WHERE idattrset = 62 GROUP BY a.idproduct, b.idattrset )t JOIN productattr a ON t.idprodattr = a.idprodattr JOIN product_attr b ON a.idattr = b.idattr) pa4 ON p.idproduct = pa4.idproduct
)t
-- END QUERY #1
-- START QUERY #2
DECLARE #listRugSizes TABLE (idmanufacturer int, RugGroup VARCHAR(500), RugSizes VARCHAR(1000))
INSERT INTO #listRugSizes
SELECT
t1.idmanufacturer
, t1.RugGroup
, STUFF(( SELECT ', ' + RugSize FROM #TempProdForSiteGoingTrim t2 WHERE t2.RugGroup = t1.RugGroup and t2.idmanufacturer = t1.idmanufacturer FOR XML PATH(''), TYPE ).value('.', 'varchar(max)'), 1, 1, '') [Values]
FROM
#TempProdForSiteGoingTrim t1
GROUP BY
t1.RugGroup
, t1.idmanufacturer
INSERT INTO [NewTableForSiteGoingTrim]
SELECT
p.idProduct
, p.sku
, p.description
, p.listPrice
, p.price
, p.imageUrl
, p.smallImageUrl
, p.sortOrder
, p.idManufacturer
, p.pgroup
, p.ruggroup
, c.idCategory
, c.idCategory [fidcategory]
, c.idParentCategory
, c.idParentCategory [gidcategory]
, pc.idParentCategory [hidCategory]
, ppc.idParentCategory [iidCategory]
, m.Name
, rp.rewrite_key [rewrite_index]
, rm.rewrite_key [rewrite_key]
, color [Color]
, collection [Collection]
, rugsize [RugSize]
, ruggroup.rugcount
, ruggroup.maxprice
, ruggroup.minprice
, rs.RugSizes
, p.rugshape
FROM
#TempProdForSiteGoingTrim p
LEFT OUTER JOIN (
SELECT
MIN(c.idCategory) [idCategory]
, c.idProduct
FROM
(
SELECT
cp.idProduct
, cp.idCategory
FROM
dbo.categories_products cp
JOIN categories c ON cp.idcategory = c.idCategory
WHERE
c.idSite = 24
) c
GROUP BY
c.idProduct
) cp ON p.idProduct = cp.idProduct
LEFT OUTER JOIN categories c ON cp.idCategory = c.idCategory
LEFT OUTER JOIN categories pc ON c.idParentCategory = pc.idCategory
LEFT OUTER JOIN categories ppc ON pc.idParentCategory = ppc.idCategory
LEFT OUTER JOIN manufacturer m ON p.idManufacturer = m.idManufacturer
LEFT OUTER JOIN (SELECT * FROM rewrite WHERE type = 3) rm ON p.idManufacturer = rm.id
LEFT OUTER JOIN (SELECT * FROM rewrite WHERE type = 1) rp ON p.idProduct = rp.id
LEFT OUTER JOIN #listRugSizes rs ON p.RugGroup = rs.RugGroup and p.idmanufacturer = rs.idmanufacturer
LEFT OUTER JOIN
(
SELECT
p.ruggroup
, p.idmanufacturer
, min(price) [minPrice]
, count(*) [RugCount]
, m.maxprice
FROM
#TempProdForSiteGoingTrim p
LEFT OUTER JOIN
(
SELECT
r.ruggroup
, r.idmanufacturer
, max(price) [maxprice]
FROM
#TempProdForSiteGoingTrim r
WHERE
r.idproduct = (SELECT MAX(idproduct) FROM #TempProdForSiteGoingTrim WHERE ruggroup = r.ruggroup AND price = r.price and idmanufacturer = r.idmanufacturer)
GROUP BY
ruggroup
, idmanufacturer
) m ON p.ruggroup = m.ruggroup and p.idmanufacturer = m.idmanufacturer
GROUP BY
p.ruggroup
, m.maxprice
, p.idmanufacturer
) ruggroup ON p.ruggroup = ruggroup.ruggroup and p.idmanufacturer = ruggroup.idmanufacturer
-- END QUERY #2
Edit
When I change the last join "ruggroup" to only group and join by column "ruggroup" and not "ruggroup" and "idmanufacturer" then it works fine.