Sql query if is null - sql

I need help to return a result if value exists or no.
UPDATED: The image show where I need help:

You can do it using CASE EXPRESSION with a LEFT JOIN .
I didn't fully understand the output you expect, but just add the columns you want:
#in_myvar = 11
select bt.username,at.postid,
CASE WHEN ct.userid is null the 0 else 1 end as c_ind
from A at
INNER JOIN B bt
ON (at.userid = bt.userid and bt.userid = #in_myvar)
LEFT JOIN C ct
ON(ct.userid = at.userid)

Use this query:
declare #in_myvar int = 11
select B.username,A.postid,(Case when C.postid = A.postid then 1 Else 0 end) as UserExists
from A inner join B on A.userID = B.UserID
Left Join C
On C.userID = A.userID
where B.userID = #in_myvar

You want a result row for each record in A. So select from A. The data from the other tables can be got with subqueries:
select
(select username from b where b.userid = a.userid) as username,
a.postid,
case when exists (select * from c where c.userid = a.userid) then 1 else 0 end as has_c
from a;
As B:A = 1:n, you can also join B, if you like that better:
select
b.username,
a.postid,
case when exists (select * from c where c.userid = a.userid) then 1 else 0 end as has_c
from a
join b on b.userid = a.userid;

Related

How can I count the same fields

I'm making a query to get the stages of a case. So Now I have three cases with 3 stages (the last stage inserted in the table user_case_stage).
SELECT DISTINCT ON (c.id)
c.id,
f.name
FROM schema.user a
JOIN schema.intern_user b ON a.id = b."userId"
JOIN schema.user_case c ON b.id = c."internUserId"
JOIN schema.user_case_stage d ON c.id = d."userCaseId"
JOIN schema.stage f ON d."stageId" = f.id
WHERE b.id = 1
ORDER BY c.id,d."createdAt" DESC
Result:
caseId stageName
1 "Pasive"
6 "Closed"
7 "Closed"
But I want something to count by stageName like this:
total stageName
1 "Pasive"
2 "Closed"
assumed your logic is correct , since you didn't provide any information, here is how you can do it:
SELECT
f.name
, count(distinct c.id) total
FROM schema.user a
JOIN schema.intern_user b ON a.id = b."userId"
JOIN schema.user_case c ON b.id = c."internUserId"
JOIN schema.user_case_stage d ON c.id = d."userCaseId"
JOIN schema.stage f ON d."stageId" = f.id
WHERE b.id = 1
group by f.name

My left join in oracle sql is not returning every element of the left table

i'm trying to get all the elements on the table B_ARTICULOS and make some calculations joining other tables (where some elements of B_ARTICULOS are not present) and I know I have to use a left join for that but I dont know what i'm doing wrong.
With this query I dont get every B_ARTICULOS, only those that are listed on the other tables
SELECT a.id, a.nombre,
CASE WHEN a.id IN dc.id_articulo THEN dc.cantidad ELSE 0 END CANTIDAD_COMPRAS,
CASE WHEN a.id IN dc.id_articulo THEN dc.cantidad * a.costo ELSE 0 END MONTO_COMPRAS,
CASE WHEN a.id IN dv.id_articulo THEN dv.cantidad ELSE 0 END CANTIDAD_VENTAS,
CASE WHEN a.id IN dv.id_articulo THEN dv.cantidad * a.precio ELSE 0 END MONTO_VENTAS
FROM B_ARTICULOS a
LEFT JOIN B_DETALLE_COMPRAS dc ON a.id = dc.id_articulo
JOIN B_COMPRAS c ON dc.id_compra = c.id
JOIN B_DETALLE_VENTAS dv ON dv.id_articulo = a.id
JOIN B_VENTAS v ON v.id = dv.id_venta
WHERE a.id IS NOT NULL;
The only explanation which I can see here is that you should be left joining to some of those other tables, beyond the second B_DETALLE_COMPRAS table. Assuming you would use left joins everywhere:
SELECT
a.id,
a.nombre,
CASE WHEN a.id IN dc.id_articulo THEN dc.cantidad ELSE 0 END CANTIDAD_COMPRAS,
CASE WHEN a.id IN dc.id_articulo THEN dc.cantidad * a.costo ELSE 0 END MONTO_COMPRAS,
CASE WHEN a.id IN dv.id_articulo THEN dv.cantidad ELSE 0 END CANTIDAD_VENTAS,
CASE WHEN a.id IN dv.id_articulo THEN dv.cantidad * a.precio ELSE 0 END MONTO_VENTAS
FROM B_ARTICULOS a
LEFT JOIN B_DETALLE_COMPRAS dc ON a.id = dc.id_articulo
LEFT JOIN B_COMPRAS c ON dc.id_compra = c.id
LEFT JOIN B_DETALLE_VENTAS dv ON dv.id_articulo = a.id
LEFT JOIN B_VENTAS v ON v.id = dv.id_venta
WHERE a.id IS NOT NULL;
You have to use left join too for other tables, like so:
...
FROM B_ARTICULOS a
LEFT JOIN B_DETALLE_COMPRAS dc ON a.id = dc.id_articulo
LEFT JOIN B_COMPRAS c ON dc.id_compra = c.id
LEFT JOIN B_DETALLE_VENTAS dv ON dv.id_articulo = a.id
LEFT JOIN B_VENTAS v ON v.id = dv.id_venta
...
Personally, I make subqueries for all the related tables that will be left joined to the main table. I grouped those tables then left join them to the main, like so:
...
FROM B_ARTICULOS a
LEFT JOIN (
SELECT dc.*
FROM B_DETALLE_COMPRAS dc
JOIN B_COMPRAS c ON dc.id_compra = c.id
) dc on a.id = dc.id_articulo
LEFT JOIN (
SELECT dv.*
FROM B_DETALLE_VENTAS dv
JOIN B_VENTAS v ON v.id = dv.id_venta
) dv ON dv.id_articulo = a.id
...

Slow query when using NOT EXIST in Query

I would like to seek some help regarding the query below.
Running this Script causes the system to timeout. The query is so slow it took 5 minutes to run for just 22 records. I believe this has something to do with "NOT IN" statement. I already look for answers here in Stackoverflow regarding this and some are suggesting using LEFT OUTER JOIN and WHERE NOT EXIST but I can't seem to incorporate it in this query.
SELECT a.UserId, COUNT(DISTINCT(a.CustomerId)) AS TotalUniqueContact
FROM [UserActivityLog] a WITH(NOLOCK)
WHERE CAST(a.ActivityDatetime AS DATE) BETWEEN '2015-09-28' AND '2015-09-30' AND a.ID
NOT IN (
SELECT DISTINCT(COALESCE(a.activitylogid, 0))
FROM [CustomerNoteInteractions] a WITH(NOLOCK)
WHERE a.reason IN ('20', '36') AND CAST(a.datecreated AS DATE) BETWEEN '2015-09-28' AND '2015-09-30' AND a.UserId IN (SELECT b.Id
FROM [User] b
WHERE b.UserType = 'EpicUser' AND b.IsEpicEmployee = 1 AND b.IsActive = 1)
)
AND a.UserId IN (
SELECT b.Id
FROM [User] b
WHERE b.UserType = 'EpicUser' AND b.IsEpicEmployee = 1 AND b.IsActive = 1)
GROUP BY a.UserId
Here is what should be an equivalent query using EXISTS and NOT EXISTS:
SELECT a.UserId,
COUNT(DISTINCT a.CustomerId) AS TotalUniqueContact
FROM [UserActivityLog] a WITH(NOLOCK)
WHERE CAST(a.ActivityDatetime AS DATE) BETWEEN '2015-09-28' AND '2015-09-30'
AND EXISTS (SELECT *
FROM [User] b
WHERE b.Id = a.UserId
AND b.UserType = 'EpicUser'
AND b.IsEpicEmployee = 1
AND b.IsActive = 1)
AND NOT EXISTS (SELECT *
FROM [CustomerNoteInteractions] b WITH(NOLOCK)
JOIN [User] c
ON c.Id = b.UserId
AND c.UserType = 'EpicUser'
AND c.IsEpicEmployee = 1
AND c.IsActive = 1
WHERE b.activitylogid = a.ID
AND b.reason IN ('20', '36')
AND CAST(b.datecreated AS DATE) BETWEEN '2015-09-28' AND '2015-09-30' )
GROUP BY a.UserId
Obviously, it's hard to understand what will truly help your performance without understanding your data. But here is what I expect:
I think the EXISTS/NOT EXISTS version of the query will help.
I think your conditions on UserActivityLog.ActivityDateTime and CustomerNoteInteractions.datecreated are a problem. Why are you casting? Is it not a date type? If not, why not? You would probably get big gains if you could take advantage of an index on those columns. But with the cast, I don't think you can use an index there. Can you do something about it?
You'll also probably benefit from indexes on User.Id (probably the PK anyways), and CustomerNoteInteractions.ActivityLogId.
Also, not a big fan of using with (nolock) to improve performance (Bad habits : Putting NOLOCK everywhere).
EDIT
If your date columns are of type DateTime as you mention in the comments, and so you are using the CAST to eliminate the time portion, a much better alternative for performance is to not cast, but instead modify the way you filter the column. Doing this will allow you to take advantage of any index on the date column. It could make a very big difference.
The query could then be further improved like this:
SELECT a.UserId,
COUNT(DISTINCT a.CustomerId) AS TotalUniqueContact
FROM [UserActivityLog] a WITH(NOLOCK)
WHERE a.ActivityDatetime >= '2015-09-28'
AND a.ActivityDatetime < dateadd(day, 1, '2015-09-30')
AND EXISTS (SELECT *
FROM [User] b
WHERE b.Id = a.UserId
AND b.UserType = 'EpicUser'
AND b.IsEpicEmployee = 1
AND b.IsActive = 1)
AND NOT EXISTS (SELECT *
FROM [CustomerNoteInteractions] b WITH(NOLOCK)
JOIN [User] c
ON c.Id = b.UserId
AND c.UserType = 'EpicUser'
AND c.IsEpicEmployee = 1
AND c.IsActive = 1
WHERE b.activitylogid = a.ID
AND b.reason IN ('20', '36')
AND b.datecreated >= '2015-09-28'
AND b.datecreated < dateadd(day, 1, '2015-09-30'))
GROUP BY a.UserId
This should get you pretty close or exactly work:
SELECT a.UserId, COUNT(DISTINCT(a.CustomerId)) AS TotalUniqueContact
FROM [UserActivityLog] a WITH(NOLOCK)
inner join [User] b with (Nolock) on a.userid = b.id
and b.UserType = 'EpicUser' AND b.IsEpicEmployee = 1 AND b.IsActive = 1
left outer join [CustomerNoteInteractions] c with (nolock) on a.id = c.activitylogid
and c.reason IN ('20', '36') AND CAST(c.datecreated AS DATE) BETWEEN '2015-09-28' AND '2015-09-30'
left outer join [User] d with (nolock) on c.userid = d.id
and d.UserType = 'EpicUser' AND d.IsEpicEmployee = 1 AND d.IsActive = 1
WHERE CAST(a.ActivityDatetime AS DATE) BETWEEN '2015-09-28' AND '2015-09-30'
and c.activitylogid is null
GROUP BY a.UserId

Select only the rows where column values appear more than once

I have a select statement similar to the following:
select *
from A
inner join B on A.id_x = B.id_x
inner join C on B.id_y = C.id_y
inner join D on C.id_z = D.id_z
where
A.date > '2014-01-01'
and A.id_y = 154
and D.id_t = 2
What I want is to do something like this and count(A.id_x) > 1, which returns only the parts of the original select which repeat on A.id_x.
Is this possible?
EDIT:
I just tried to solve it using temp tables, with the code I got from T-SQL Insert into table without having to specify every column
Select * Into
#tmpBigTable
From [YourBigTable]
But I got an error message because my tables have the same column names, A.id_x and B.id_x, for example.
"Column names in each table must be unique."
Is there some way to force the issue, or declare arbitrary naming extensions?
select *
from A
inner join B on A.id_x = B.id_x
inner join C on B.id_y = C.id_y
inner join D on C.id_z = D.id_z
where
A.date > '2014-01-01'
and A.id_y = 154
and D.id_t = 2
AND A.id_x IN
(
SELECT A.id_x FROM A
GROUP BY A.id_x
HAVING count(A.id_x)>1);
You can do this with window functions:
select *
from (select *, count(*) over (partition by A.id_x) as cnt
from A inner join
B
on A.id_x = B.id_x inner join
C
on B.id_y = C.id_y inner join
D
on C.id_z = D.id_z
where A.date > '2014-01-01' and A.id_y = 154 and D.id_t = 2
) abcd
where cnt > 1;

mysql query to three tables, want to use JOIN instead subquery

I want to use join instead subquery to find the trade id not exist on trade_log filtered by ip and current date for mysql syntax below.
SELECT plug.id as a,
plug.url as b,
trade.id as c
FROM plug, trade
WHERE trade.id = plug.trade_id
AND trade.id NOT IN (SELECT trade_log.trade_id
FROM trade_log
WHERE trade_log.ip = '".$ip."'
AND trade_log.log_date = CURDATE())
AND trade.status = 1
AND plug.status = 1
ORDER BY plug.weight DESC
LIMIT 1
Please help me...
Use:
SELECT p.id as a,
p.url as b,
t.id as c
FROM PLUG p
JOIN TRADE t ON t.id = p.trade_id
AND t.status = 1
LEFT JOIN TRADE_LOG tl ON tl.trade_id = t.id
AND tl.ip = mysql_real_escape_string($ip)
AND tl.log_date = CURDATE()
WHERE p.status = 1
AND tl.ip IS NULL
ORDER BY p.weight DESC
LIMIT 1
Same as OMG Ponies:
SELECT p.id as a,
p.url as b,
t.id as c
FROM plug p
INNER JOIN trade t ON (t.id = p.trade_id AND t.status = 1)
LEFT JOIN trade_log l ON (l.trade_id = t.id AND l.ip = '".$ip."' AND l.log_date = CURDATE())
WHERE p.status = 1 AND l.trade_id IS NULL
ORDER BY p.weight DESC
LIMIT 1