Query the results of another query - sql

I'm writing a query to build an audience for a abandoned cart email. So far, I have the script below, which gives me the correct result (as far as I can tell). However, if possible I would like to query the final result, in order to:
Check if there are multiples of the same email_address that exist in the
output
If true, select the email_address with the oldest (min) modified_date
email_address exist in table a, but I want to use the modified_date from table c.
Can anybody assist me?
Also, I'm not an sql dev, so if you could please explain your answer to help me learn, I would grateful.
Thanks in advance.
SELECT DISTINCT a.guid,
a.customer_id,
a.email_address,
c.product_code,
c.purchase_url,
c.modified_date
FROM (SELECT LIST.guid,
LIST.customer_id,
LIST.email_address
FROM $a$ LIST) a
INNER JOIN (SELECT BASE.guid
FROM $b$ BASE) b
ON a.guid = b.guid
INNER JOIN (SELECT SUPP.customer_id,
SUPP.product_code,
SUPP.purchase_url,
SUPP.modified_date
FROM $c$ SUPP) c
ON a.customer_id = c.customer_id
LEFT JOIN (SELECT EXCL.product_code
FROM $d$ EXCL) d
ON c.product_code = d.product_code
WHERE d.product_code IS NULL
AND c.product_code IS NOT NULL
AND c.modified_date = (SELECT Max(J.modified_date)
FROM $c$ J
WHERE J.customer_id = c.customer_id)
AND Trunc(c.modified_date) = Trunc(sysdate) - 1

If you just need email_address with mininum modified_date you can use below query:
SELECT DISTINCT a.guid,
a.customer_id,
a.email_address,
c.product_code,
c.purchase_url,
min(c.modified_date)over(partition by a.email_address)modified_date
FROM (SELECT LIST.guid,
LIST.customer_id,
LIST.email_address
FROM $a$ LIST) a
INNER JOIN (SELECT BASE.guid
FROM $b$ BASE) b
ON a.guid = b.guid
INNER JOIN (SELECT SUPP.customer_id,
SUPP.product_code,
SUPP.purchase_url,
SUPP.modified_date
FROM $c$ SUPP) c
ON a.customer_id = c.customer_id
LEFT JOIN (SELECT EXCL.product_code
FROM $d$ EXCL) d
ON c.product_code = d.product_code
WHERE d.product_code IS NULL
AND c.product_code IS NOT NULL
AND c.modified_date = (SELECT Max(J.modified_date)
FROM $c$ J
WHERE J.customer_id = c.customer_id)
AND Trunc(c.modified_date) = Trunc(sysdate) - 1

Related

Subquery problem when using WHERE in secondary SELECT

I have problem with query.
SELECT
a.code,
b.codename,
(SELECT COUNT(b.IdNum)
FROM
(SELECT *
FROM NumTable
WHERE YEAR(DateOfPoint) = 2019)) AS CountNumber
FROM
NumTable b
JOIN
CodeTable a ON a.id = b.id
WHERE
a.SellYear IS NOT NULL
My First question is about CountNumber is it ok ? I need to count only those b.IdNum that have DateOfPoint = 2019. It should only be to this field not to any other in this query, thats why I didn't use it in the end in WHERE.
Second question is about CountNumber too becouse I still get error msg that I got there incorrect syntax I was looking for it for about hour and couldn't find it.
Thanks
not sure what you are trying to get here but I think group by is more logicly here
SELECT a.code
,b.codename
,Sum(case when b.DateOfPoint= 2019 then 1 else 0) as CountNumber
FROM NumTable b
JOIN CodeTable a ON a.id = b.id
WHERE a.SellYear IS NOT NULL
group by a.code,b.codename
you will get a row for each code and codename and the number of dateofPoint in 2019 that it have if there are none it will return 0
You can use this query. I think, it will work for you:
SELECT a.code,
b.codename
FROM
NumTable b
JOIN
CodeTable a ON a.id = b.id
JOIN
(SELECT *
FROM NumTable
WHERE YEAR(DateOfPoint) = 2019) c ON c.id = b.id
JOIN
(SELECT id, COUNT(b.IdNum) FROM c) d ON c.id = d.id
WHERE
a.SellYear IS NOT NULL
You can use a window function:
SELECT c.code, n.codename, c.cnt_2019
FROM (SELECT n.*,
SUM(CASE WHEN YEAR(DateOfPoint) = 2019 THEN 1 ELSE 0 END) as cnt_2019
FROM NumTable n
) n JOIN
CodeTable c
ON c.id = n.id
WHERE c.SellYear IS NOT NULL;
Note that I also changed the table aliases so they are abbreviations for the table names rather than arbitrary letters.

avoid repeating condition in select query

I have the following query to be executed on postgresql
SELECT COUNT(DISTINCT id_client) FROM contract c
INNER JOIN bundle b ON c.bundle_id = b.id
INNER JOIN payment_method pm ON pm.id = c.payment_method_id
WHERE country_id=1 AND b.platform_id=1 AND pm.name <> 'RIB'
AND CONDITION_1
AND id_client NOT IN (
SELECT id_client FROM contract c1
INNER JOIN bundle b1 ON (c1.bundle_id = b1.id)
INNER JOIN payment_method pm1 ON pm1.id = c1.payment_method_id
WHERE c1.country_id=1 AND b1.platform_id=1 AND pm1.name <> 'RIB'
AND CONDITION_2);
I don't like it because it's the same query repeated twice except of CONDITION_1 and CONDITION_2 (and I have another example where it's repeated 3 times).
It's also very slow as well.
I tried to rewrite it as the following:
WITH
filter_cpm AS (
SELECT * FROM contract c
INNER JOIN bundle b ON b.id = c.bundle_id
INNER JOIN payment_method pm ON pm.id = c.payment_method_id
WHERE c.country_id = 1 AND b.platform_id = 1 AND pm.name <> 'RIB'
)
SELECT COUNT(DISTINCT id_client) FROM filter_cpm
WHERE CONDITION_1
AND id_client NOT IN (
SELECT id_client FROM filter_cpm
WHERE CONDITION_2);
Now it's DRY but it's two times slower.
How can I re-write the query to have the same (or better) performance?
EDIT: I cannot join two conditions with AND. For example if CONDITION_1 and CONDITION_2 are VIP, then I want to select clients who were re-qualified from NOT VIP to VIP.
You can select from the common table expression twice, using an outer join:
WITH filter_cpm AS (SELECT *
FROM CONTRACT c
INNER JOIN BUNDLE b
ON b.ID = c.BUNDLE_ID
INNER JOIN PAYMENT_METHOD pm
ON pm.ID = c.PAYMENT_METHOD_ID
WHERE c.COUNTRY_ID = 1 AND
b.PLATFORM_ID = 1 AND
pm.NAME <> 'RIB')
SELECT COUNT(DISTINCT fc1.ID_CLIENT)
FROM filter_cpm fc1
LEFT OUTER JOIN filter_cpm fc2
ON fc2.ID_CLIENT = fc1.ID_CLIENT AND
CONDITION_2
WHERE fc1.CONDITION_1 AND
fc2.ID_CLIENT IS NULL
Best of luck.

First query data is used in second query

I have a query get_product:
select A.product_id,
A.name, A.description, A.type_id,
B.series_name
product_data A
inner join
series B
on A.series_raw_id = B.series_raw_id
where A.product_id = 503061
and A.registration_type_id = 4
order by B.series_name
and second query
select B.series_name,
A.TEMPACC_STATUS
FROM
ACCESS_FACT A
inner join
**get_product** B
on A.TEMPACC_PRODUCT_ID = B.product_id
where A.TEMPACC_DATE_ID between 6717 and 6808
and A.reason_id_total = 0
group by Series_name,
STATUS
In the second query we use data from first query (get_product is the first query). How do I get that table here?
You could use the WITH clause.
For example,
WITH get_product AS
(SELECT A.product_id,
A.name,
A.description,
A.type_id,
B.series_name product_data A
INNER JOIN series B
ON A.series_raw_id = B.series_raw_id
WHERE A.product_id = 503061
AND A.registration_type_id = 4
ORDER BY B.series_name
)
SELECT B.series_name,
A.TEMPACC_STATUS
FROM ACCESS_FACT A
INNER JOIN get_product B
ON A.TEMPACC_PRODUCT_ID = B.product_id
WHERE A.TEMPACC_DATE_ID BETWEEN 6717 AND 6808
AND A.reason_id_total = 0
GROUP BY Series_name,
STATUS;
Or, you could use an INLINE VIEW
SELECT B.series_name,
A.TEMPACC_STATUS
FROM ACCESS_FACT A
INNER JOIN
(SELECT A.product_id,
A.name,
A.description,
A.type_id,
B.series_name product_data A
INNER JOIN series B
ON A.series_raw_id = B.series_raw_id
WHERE A.product_id = 503061
AND A.registration_type_id = 4
ORDER BY B.series_name
) B ON A.TEMPACC_PRODUCT_ID = B.product_id
WHERE A.TEMPACC_DATE_ID BETWEEN 6717 AND 6808
AND A.reason_id_total = 0
GROUP BY Series_name,
STATUS;

Using a group by to group a select statement

Using a group by to group a select stament
SELECT
k.Ivalue, k.JOBDESCRIPTION ,
count( k.Ivalue) as TOTAL
FROM
(SELECT
a."ID" as Ivalue, b."JOBDESCRIPTION", rq."CURRENTSTATUS"
FROM
tblG2o_Requests a
INNER JOIN
tblG2o_JOBS b ON a."JOBPOSTID" = b."ID"
INNER JOIN
(SELECT
r.REQUESTID, ir."CURRENTSTATUS"
FROM
TBLG2O_RESULTSPOOL r
INNER JOIN
tblG2o_Requests ir ON r.RequestID = ir."ID"
WHERE
r.ShortListed = '1') rq ON rq.REQUESTID = a."ID"
WHERE
"ACTIVE" = '1'
AND "DATECOMPLETED" IS NULL
ORDER BY
"REQUESTDATE" DESC) k
GROUP BY
k.JOBDESCRIPTION
What is the question? You seem to be missing the group by clause, and you do not need double quotes around field names unless you have spaces in them, and even then, if TSQL for example, you would use [] in preference.
I had to remove an ORDER BY in the subquery, that isn't allowed unless other conditions demand it (like TOP n in TSQL)
SELECT
k.Ivalue
, k.JOBDESCRIPTION
, COUNT(k.Ivalue) AS TOTAL
FROM (
SELECT
a.ID AS Ivalue
, b.JOBDESCRIPTION
, rq.CURRENTSTATUS
FROM tblG2o_Requests a
INNER JOIN tblG2o_JOBS b
ON a.JOBPOSTID = b.ID
INNER JOIN (
SELECT
r.REQUESTID
, ir.CURRENTSTATUS
FROM TBLG2O_RESULTSPOOL r
INNER JOIN tblG2o_Requests ir
ON r.RequestID = ir.ID
WHERE r.ShortListed = '1'
) rqenter
ON rq.REQUESTID = a.ID
WHERE ACTIVE = '1'
AND DATECOMPLETED IS NULL
) k
GROUP BY
k.Ivalue
, k.JOBDESCRIPTION
Finally worked
SELECT
k.Ivalue
, l.JOBDESCRIPTION
, k.TOTAL,
k.CURRENTSTATUS
FROM (
SELECT
a.ID AS Ivalue
,b.ID as JobPostID
, rq."CURRENTSTATUS"
,COUNT(a.ID) AS TOTAL
FROM tblG2o_Requests a
INNER JOIN tblG2o_JOBS b
ON a."JOBPOSTID" = b.ID
INNER JOIN (
SELECT
r."REQUESTID"
, ir."CURRENTSTATUS"
FROM TBLG2O_RESULTSPOOL r
INNER JOIN tblG2o_Requests ir
ON r."REQUESTID" = ir.ID
WHERE r."SHORTLISTED" = 1
) rq
ON rq."REQUESTID" = a.ID
WHERE ACTIVE = '1'
AND DATECOMPLETED IS NULL
GROUP BY
a.ID ,b.ID
, rq."CURRENTSTATUS" ) k
inner join tblG2o_JOBS l on k.JobPostID =l.ID
enter code here

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.