How to find exact match of multiple values in a column? - sql

I need a query that returns all picklists that only have the specified UPCs (e.g. 038447302 and 00934831). The query I am currently have is using WHERE IN and so it returns all picklists that have the specified UPCs as well as any other UPC in the picklist.
SELECT
a.order_id,
a.id AS picklist_id,
SUM(p.quantity),
p.upc,
pick_zone,
a.STATUS
FROM
picklists a
INNER JOIN picklist_items p ON p.picklist_id = a.id
INNER JOIN warehouse_orders f ON a.order_id = f.id
WHERE
a.STATUS IN ('dropped')
AND f.status != 'cancelled'
and p.upc IN('038447302', '00934831')
GROUP BY
a.STATUS,
a.picklist_group_id,
a.id,
a.order_id,
pick_zone

Related

Replace correlated subquery with CTE and JOIN

I am trying to rewrite a query which has a correlated subquery, the idea is to replace it with a CTE and join it later.
I have three tables, tbl_transaction, tbl_beneficiaries and tbl_reg_countries. The current (in short) SQL looks like the following.
SELECT
t.USER_ID,
t.TRANSACTION
FROM tbl_transactions t
JOIN tbl_beneficiaries b ON b.ID = t.USER_ID
WHERE b.COUNTRY NOT IN (
SELECT rc.country
FROM tbl_reg_countries rc
WHERE rc.id = t.USER.ID)
My goal is to query only those transactions for each user where the transaction happens outside of the registered countries. So a user may registered X,Y,Z country but had business with Q. In that case only Q should be returned. How could this be replaced with a CTE/JOIN?
I assume both tbl_beneficiaries.COUNTRY and tbl_reg_countries.COUNTRY are not nullable. You can use a LEFT JOIN with NULL test to detect never matching rows
SELECT
t.USER_ID,
t.TRANSACTION
FROM tbl_transactions t
JOIN tbl_beneficiaries b ON b.ID = t.USER_ID
LEFT JOIN tbl_reg_countries rc ON rc.id = t.USER_ID AND b.COUNTRY = rc.country
WHERE rc.country IS NULL
I would try rewriting query with "with"
Like this:
With a As
(Select
Distinct rc.country
From tbl_reg_countries rc
Inner Join tbl_transactions t on rc.id = t.USER.ID
)
Select
t.USER_ID,
t.TRANSACTION
From tbl_transactions t
Inner Join tbl_beneficiaries b On b.ID = t.USER_ID
Where b.COUNTRY Not In (select * from a)

ERROR: invalid reference to FROM-clause entry for table "oth"

I have a problem with this query
SELECT DISTINCT(oth.book) FROM book_meta_keywords oth,
(SELECT bmk.meta_keyword AS metaKeyword, bmk.book AS book FROM books b
INNER JOIN customers_books cvb ON cvb.book = b.id
INNER JOIN book_meta_keywords bmk ON bmk.book = b.id
WHERE cvb.customer = 1 ) AS allCustomerPurchasedBooksMeta
INNER JOIN books b ON b.id = oth.book
WHERE oth.meta_keyword = allCustomerPurchasedBooksMeta.metaKeyword AND oth.book != allCustomerPurchasedBooksMeta.book AND b.status = 'GOOD'
I am getting below error for this query.
ERROR: invalid reference to FROM-clause entry for table "oth"
LINE 6: INNER JOIN books b ON b.id = oth.book
^
HINT: There is an entry for table "oth", but it cannot be referenced from this part of the query.
, Time: 0.002000s
But if I run the below query it works
SELECT DISTINCT(oth.book) FROM book_meta_keywords oth,
(SELECT bmk.meta_keyword AS metaKeyword, bmk.book AS book FROM books b
INNER JOIN customers_books cvb ON cvb.book = b.id
INNER JOIN book_meta_keywords bmk ON bmk.book = b.id
WHERE cvb.customer = 1 ) AS allCustomerPurchasedBooksMeta
WHERE oth.meta_keyword = allCustomerPurchasedBooksMeta.metaKeyword AND oth.book != allCustomerPurchasedBooksMeta.book
Can anyone help me why... query is basically trying to get similar books based on purchased books based on their meta keywords.
thanks.
This is your FROM clause:
FROM
book_meta_keywords oth,
(SELECT ... FROM ... WHERE ...) AS allCustomerPurchasedBooksMeta
INNER JOIN books b ON b.id = oth.book
You are mixing explicit and implicit joins (the latter is denoted by the comma). Don't. They have different prescendence rules and the query planner ends up evaluating the the second condiiton before oth was seen.
As for how to solve this: assuming that the logic is indeed what you want, that's a lateral join:
FROM
book_meta_keywords oth
CROSS JOIN LATERAL (SELECT ... FROM ... WHERE ...) AS allCustomerPurchasedBooksMeta
INNER JOIN books b ON b.id = oth.book
I suspect, however, that your query could be further simplified. You might want to ask another question for this, explaning the purpose of the query and providing a minimum reproducible example.
You are missing join
SELECT DISTINCT oth.book FROM book_meta_keywords oth join
(SELECT bmk.meta_keyword AS metaKeyword, bmk.book AS book FROM books b
INNER JOIN customers_books cvb ON cvb.book = b.id
INNER JOIN book_meta_keywords bmk ON bmk.book = b.id
WHERE cvb.customer = 1 ) AS allCustomerPurchasedBooksMeta
on oth.meta_keyword = allCustomerPurchasedBooksMeta.metaKeyword and
oth.book != allCustomerPurchasedBooksMeta.book
INNER JOIN books b ON b.id = oth.book
WHERE b.status = 'GOOD'
Well it can work :
SELECT DISTINCT oth.book
FROM book_meta_keywords oth
INNER JOIN books b ON b.id = oth.book
, (SELECT bmk.meta_keyword AS metaKeyword, bmk.book AS book
FROM books b
INNER JOIN customers_books cvb ON cvb.book = b.id
INNER JOIN book_meta_keywords bmk ON bmk.book = b.id
WHERE cvb.customer = 1 ) AS allCustomerPurchasedBooksMeta
WHERE oth.meta_keyword = allCustomerPurchasedBooksMeta.metaKeyword
AND oth.book != allCustomerPurchasedBooksMeta.book
AND b.status = 'GOOD'
But does this do what you need...

How to construct a SQL sub query in SQL Server 2008?

I have requirement to extract total number of rows from a table - ci_periodicBillings only for clients where they have rows from a particular date range from another table - ci_invoiceHeaders. I am using MS SQL Server 2008, connecting via ODBC.
I have created a subquery which works but only if the total number of rows from ci_periodicBillings is 1. I'm finding if there is more than 1 result from ci_periodicBillings, it's multiplying the rows found by the number of rows meeting the criteria from ci_invoiceHeaders.
I only want to show only the rows from ci_periodicBillings without any multiplication if the criteria is met in ci_invoiceHeaders. I'm sure there is an easy solution to this but I can't see the wood from the trees at the moment.
There are a few other tables used for listing purposes only (i.e. facilities/clients etc)
SQL is here:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
SELECT
b.name,
b.forename,
b.surname,
a.client,
cast(a.BILLSTART as DATE) as BILLSTART,
cast(a.ENDBILL as DATE) as ENDBILL,
a.RATE
FROM ci_periodicBillings as a
inner join
(select f.name,
c.surname,c.forename,ih.client,ih.invoiceDate
FROM ci_invoiceHeaders ih
LEFT JOIN ci_invoiceDetails id ON ih.invoiceNo = id.id
INNER JOIn cs_clients c ON ih.client = c.guid
INNER JOIN cs_facilities f ON c.facility = f.guid
group by f.name, c.surname,
c.forename, ih.client, ih.invoiceDate)
as b
on a.client = b.client
WHERE b.invoiceDate between '2017-08-01' and '2018-01-31'
order by a.client
Any ideas please?
Try this:
SELECT b.name, b.forename, b.surname, a.client,
cast(a.BILLSTART AS DATE) AS BILLSTART,
cast(a.ENDBILL AS DATE) AS ENDBILL, a.RATE
FROM ci_periodicBillings AS a inner join
(SELECT f.name, c.surname,c.forename,ih.client,DATE(ih.invoiceDate) invoiceDate
FROM ci_invoiceHeaders ih
LEFT JOIN ci_invoiceDetails id ON ih.invoiceNo = id.id
INNER JOIn cs_clients c ON ih.client = c.guid
INNER JOIN cs_facilities f ON c.facility = f.guid
WHERE ih.invoiceDate BETWEEN '2017-08-01' AND '2018-01-31'
GROUP BY f.name, c.surname,c.forename,ih.client,DATE(ih.invoiceDate)) AS b
ON a.client = b.client
ORDER BY a.client;

How to display the accurate sum when using 2 inner joins?

I am trying to get the results:
Quote = 12345
Total Assets = 14
Total Ordered = 22
When I run the queries separately I get the correct results, but when I put the two queries together my results are off (this is because the tables b and c do not represent each other)
my table summaries are as follows:
Select a.Quote, SUM(b.Quantity) As 'Total Assets'
FROM a
INNER JOIN b ON b.aId = a.Id
GROUP By a.Quote
Result: 12345 : 14
Select a.Quote, SUM(c.Quantity) As 'Total Ordered'
FROM a
INNER JOIN c on c.aId = a.Id
GROUP By a.Quote
Result: 12345 : 22
However, when I put them together:
Select a.Quote, SUM(b.Quantity)As 'Total Assets',SUM(c.Quantity) As 'Total Ordered'
FROM a
INNER JOIN b on b.Aid = a.Id
INNER JOIN c on c.Aid = a.Id
GROUP BY a.Quote
Result 12345 : 56 : 308
I played with the group by but was never able to get the proper result. Any thoughts?
So far the solution I came up with is
With abc AS
(
Select a.Quote, SUM(b.Quantity) As 'Total Assets'
FROM a
INNER JOIN b ON b.aId = a.Id
GROUP By a.Quote
)
SELECT abc.* , SUM(c.Quantity) As ' Total Ordered'
FROM abc
INNER JOIN c ON c.aid = a.Id
GROUP BY (all in abc)
It doesn't seem like the best way to get the results though..
Maybe use Left JOIN. The INNER JOIN will repeat rows of b and c. Also, try to see the result of:
Select a.Quote, b.Quantity As 'Total Assets', c.Quantity As 'Total Ordered'
FROM a
INNER JOIN b on b.Aid = b.Id
INNER JOIN c on c.Aid = c.Id
GROUP BY a.Quote
And check if it's the right results that are computed. Then compare it against:
Select a.Quote, b.Quantity As 'Total Assets', c.Quantity As 'Total Ordered'
FROM a
LEFT JOIN b on b.Aid = b.Id
LEFT JOIN c on c.Aid = c.Id
GROUP BY a.Quote

Inner Join (Select . From)

I need to get the last record posted by users. The following query below would get the information I need if I want if I can do order by before group by
select a.client_id, a.client, b.title, b.type, b.created
from profile_users a, node b
where a.uid = b.uid
and b.type = 'event'
and a.status=1
and a.client_id in (select c.client_id
from profile_users c, follows d
where c.uid = d.followed_id
and d.following_id =3)
group by a.client_id
order by a.client_id,
b.created desc
I tried rewriting the query using inner join but not getting the desired result. I need to write this query so that I am getting the client_id after checking records on follows table. I need some assistance to fix this query.
select b.client_id, b.client, a.title, a.created
from node a
inner join profile_users b on a.uid=b.uid
inner join (select c.client_id
from profile_users c
inner join follows d on c.uid=d.followed_id
where c.status = 1
and d.following_id = 3
order by c.client_id
) as X1
Use sql "partition by " it will allow you to sort your records without group by.
http://learnsqlserver.in/2/Partition-By-Clause.aspx
This is best to use over group by.
You need to use a co-related subquery in order to determine the last post:
select a.client_id, a.client, b.title, b.type, b.created
from profile_users a
join node b on a.uid = b.uid
where b.type = 'event'
and a.status=1
and a.client_id in (select c.client_id
from profile_users c
join follows d on c.uid = d.followed_id
where d.following_id = 3)
and b.created = (select max(n2.created)
from node n2
where n2.uid = a.uid)
order by a.client_id,
b.created desc
I also changed your old-style implicit joins in the where clause to explicit ones using the 'JOIN' keyword.