Subquery problem when using WHERE in secondary SELECT - sql

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.

Related

Query the results of another query

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

How to calculate the z score after joining 3 tables in MySQL

I have joined three tables A, B, D using this query,
SELECT [A].ID, [A].Surname, [A].[Given Name], [B].[Pre-U Grade], [D ].[Total Score], [B].[score]
FROM ([A] LEFT JOIN [D] ON [A].ID = [D].[Student ID]) INNER JOIN [B-Results] ON [A].ID = [B].ID
WHERE ((([B].[Pre-U Grade])=IsNumeric([B]![Pre-U Grade])) AND (([D].[Total Score]) Is Not Null) AND (([A].Status) Not In ("REJECTED","OFFERED","WITHDRAWN"))) OR ((([B].[Pre-U Grade])>"0") AND (([D].[Total Score]) Is Not Null) AND (([A].Status) Not In ("REJECTED","OFFERED","WITHDRAWN")))
ORDER BY [D].[Date] DESC;
After joining the tables, the z-score for the 3 numerical columns needs to be calculated.
I came across this example
Calculating Z-Score for each row in MySQL? (simple)
but i didnt know how to use the code given for my problem statement. Can someone kindly help me with this?
SELECT
(pre-u_grade - AVG(pre-u_grade))/STD(pre-u_grade) z_pre-u_grade,
(total_score- AVG(total_score))/STD(total_score) z_total_score,
(score- AVG(score))/STD(score) z_score,
(SELECT
a.id,
a.surname,
a.given_name,
pre-u_grade,
total_score,
score
FROM
a
LEFT JOIN
d
ON
a.id = d.student id)
INNER JOIN
b.results
ON
a.id = b.id
WHERE
(
( b.pre-u_grade = ISNUMERIC(b ! pre-u_grade)
AND d.total score IS NOT NULL
AND a.status NOT IN ( "rejected", "offered", "withdrawn) )
OR
( b.pre-u_grade > 0
AND d.total score ) IS NOT NULL
AND a.status NOT IN ( "rejected", "offered", "withdrawn" ) )
)
ORDER BY
d.date DESC) result;
Try this.

Select an ID where there is only one row and that row is a specific value

I have this query. There's a lot of joins because I am checking if an ID is linked to any of those tables.
Currently, this query shows me any ID's that are not linked to any of those tables. I would like to add to it so that it also shows any IDs that are linked to the d table, but only if there is only 1 row in the D table and the type in the D field is 'member'.
SELECT
c.ID,
c.location,
c.pb,
c.name,
c.surname
FROM c
LEFT JOIN l on c.rowno = l.rowno
LEFT JOIN d on c.rowno = d.rowno
LEFT JOIN t on c.rowno = t.rowno
LEFT JOIN cj ON (c.rowno = cj.rowno OR c.rowno = cj.rowno2)
LEFT JOIN dj ON c.rowno = d.rowno
LEFT JOIN lg ON c.rowno = lg.rowno
LEFT JOIN tj ON c.rowno = tj.rowno
WHERE
c.status != 'closed'
AND l.rowno IS NULL
AND d.rowno IS NULL
AND t.rowno IS NULL
AND cj.rowno IS NULL
AND dj.rowno IS NULL
AND lg.rowno IS NULL
AND tj.rowno IS NULL
My first thought is to just add
WHERE D.type = 'member'
But that gives me all IDs that have a row with D.type = member (they could have 10 rows with all different types, but as long as 1 of those has type = member it shows up). I want to see ID's that ONLY have d.type = member
I'm sorry if I'm wording this badly, I'm having trouble getting this straight in my head. Any help is appreciated!
I would use exists for all conditions except the one on the D table:
SELECT c.*
FROM c JOIN
(SELECT d.rownum, COUNT(*) as cnt,
SUM(CASE WHEN d.type = 'Member' THEN 1 ELSE 0 END) as num_members
FROM t
GROUP BY d.rownum
) d
ON c.rownum = d.rownum
WHERE c.status <> 'closed' AND
NOT EXISTS (SELECT 1 FROM t WHERE c.rowno = t.rowno) AND
NOT EXISTS (SELECT 1 FROM l WHERE c.rowno = l.rowno) AND
. . .
I find NOT EXISTS is easier to follow logically. I don't think there is a big performance difference between the two methods in SQL Server.

Window function issue - max over partition

I try to rewrite such SQL statements (with many subqueries) to more efficient form using outer join and max/count/... over partition. Old statements:
select a.ID,
(select max(b.valA) from something b where a.ID = b.ID_T and b.status != 0),
(select max(b.valB) from something b where a.ID = b.ID_T and b.status != 0),
(select max(b.valC) from something b where a.ID = b.ID_T and b.status != 0),
(select max(b.valD) from something b where a.ID = b.ID_T)
from tool a;
What is important here - there is different condition for max(b.valD). Firstly I didn't noticed this difference and write something like this:
select distinct a.ID,
max(b.valA) over (partition by b.ID_T),
max(b.valB) over (partition by b.ID_T),
max(b.valC) over (partition by b.ID_T),
max(b.valD) over (partition by b.ID_T),
from tool a,
(select * from something
where status != 0) b
where a.ID = b.ID_T(+);
Could I use somewhere in max over partition this condition of b.status != 0 ? Or should I better add 3rd table to join like this:
select distinct a.ID,
max(b.valA) over (partition by b.ID_T),
max(b.valB) over (partition by b.ID_T),
max(b.valC) over (partition by b.ID_T),
max(c.valD) over (partition by c.ID_T),
from tool a,
(select * from something
where status != 0) b,
something c
where a.ID = b.ID_T(+)
and a.ID = c.ID_T(+);
The issue is with selecting and joining millions of rows, my example is just simplification of my query. Could anyone help me to achieve more efficient sql?
You could try to do this using CASE:
select a.ID,
max(CASE WHEN b.status=0 THEN b.valA END),
max(CASE WHEN b.status=0 THEN b.valB END),
max(CASE WHEN b.status=0 THEN b.valC END),
max(b.valD)
from tool a
left join something b ON( b.ID_T = a.ID )
group by a.ID;
Note that I replaced your implicit join by the "new" join-syntax for better readability.
One more way is to use JOIN and group by subquery:
select a.ID,
b.MAX_A,
b.MAX_B,
b.MAX_C,
b2.MAX_D
from tool a
LEFT JOIN
(
SELECT ID_T,max(valA) MAX_A, max(valB) MAX_B, max(valC) MAX_C
FROM something
WHERE status != 0
GROUP BY ID_T
) b
ON a.ID=b.ID_T
LEFT JOIN
(
SELECT ID_T, max(valD) MAX_D
FROM something
GROUP BY ID_T
) b2
ON a.ID=b2.ID_T

An error : Subquery returned more than 1 value

I am getting the error-msg when i try the following code:
SELECT COUNT(*) FROM [ServerName].[dbo].[TableName1] B
WHERE right(B.TableName1, 2) = '34' AND
B.UnitId=
(select distinct D.UnitId
from [ServerName].[dbo].[TableName2] D
INNER JOIN #temp E ON D.UnitId=E.UnitId)
Does anyone know how to solve it? It says the subquery returned more than 1 value. The temp-table is created and contains a selection of the number individuals that I want to count, by unitId.
Try using a join instead of the subquery:
SELECT COUNT(*)
FROM [ServerName].[dbo].[TableName1] B
INNER JOIN [ServerName].[dbo].[TableName2] D ON B.UnitId = D.UnitId
INNER JOIN #temp E ON D.UnitId = E.UnitId
WHERE RIGHT(B.TableName1, 2) = '34'
The subquery (select distinct) has more than one value returned. As such B.UnitId cannot equal more than one value.
You can use IN if its ok for B.UnitId to have more than one value.
SELECT COUNT(*)
FROM [ServerName].[dbo].[TableName1] B
WHERE right(B.TableName1, 2) = '34'
AND B.UnitId in (select D.UnitId
from [ServerName].[dbo].[TableName2] D
INNER JOIN #temp E ON D.UnitId=E.UnitId)
Distinct becomes superfluous when you use IN.