Correlated query: select where condition not max(condition in inner query) - sql

I am trying to select all the rows where the userName and groupId is duplicated, and the userId is not the max userId for that userName/groupId combination. Here is my code so far:
select *
from userTable u
where exists
(select *
from userTable u1
where userName <> '' and userName is not null
and u.userName = u1.userName and u.groupId = u1.groupId
and u.userId <> max(u1.userId)
group by userName, groupId
having count(*) > 1)
order by userName
However, the line:
and u.userId <> u1.max(userId)
is giving me an error.
What is the right way to do this query?

SELECT u.*
FROM (
SELECT userName, groupId, MAX(userId) AS maxId
FROM userTable
GROUP BY
userName, groupId
HAVING COUNT(*) > 1
) q
JOIN userTable u
ON u.userName = q.userName
AND u.groupId = q.groupId
AND u.userId <> q.maxId

This should do it, I think:
select t.*
from dbo.UserTable t
join ( select userName , groupID , maxUserID = max(userID)
from dbo.UserTable x
group by userName , groupID
having count(*) > 1
) dupes on dupes.userName = t.userName
and dupes.groupID = t.groupID
and dupes.maxUserID > t.userID

Related

How convert multiple results rows to single row SQL with respective values

I have two tables Users and UserAttributes in SQL DB.
Table have structure like
Out required is
My attempted query
Select * from (
Select u.UserId,u.Username,u.UserEmail,ua.objectName,ua.objectValue
from Users u join userAttribute on u.UserId=ua.UserId
where ua.objectName='city' or pv.objectName='phone')) results
PIVOT (count(UserId)
For objectName IN ([city],[phone])) As pivot_table;
Current output
Still it is an double entry also for the reason I am not aware the city and phone results are in 0 and 1 (boolean).
Please help getting the desired output.
You can do aggregation :
select u.UserId, u.username, u.usermemail,
max(case when ua.objectname = 'city' then objvalue end),
max(case when ua.objectname = 'phone' then objvalue end)
from User u join
userAttribute ua
on u.UserId = ua.UserId
group by u.UserId, u.username, u.usermemail;
You can use conditional aggregation to extract the values from the UserAttributes table:
SELECT u.userid, u.userName, u.userEmail,
MAX(CASE WHEN ua.objName = 'city' THEN ua.objValue END) AS city,
MAX(CASE WHEN ua.objName = 'phone' THEN ua.objValue END) AS phone,
FROM Users u
JOIN UserAttributes ua ON ua.userid = u.userid
GROUP BY u.userid, u.userName, u.userEmail
To pivot just two columns, joins is convenient:
select u.*, uac.objvalue as city, uap.objvalue as phone
from users u left join
userattributes uac
on uac.userid = u.userid and
uac.objname = 'city' left join
userattributes uap
on uap.userid = u.userid and
uap.objname = 'phone';
If you want only rows with matches, then add:
where uac.objvalue is not null or uap.objvalue is not null
If you have more columns, then join and group by is probably a better approach:
select u.*, au.*
from users u join
(select ua.userid,
max(case when objname = 'city' then objvalue end) as city,
max(case when objname = 'phone' then objvalue end) as phone
from userattributes ua
group by ua.userid
) ua
on u.userid = ua.userid;
Please try following query. Hope this will help
DECLARE #Users table(userid int, username varchar(50))
insert into #Users select 1,'Shiv'
insert into #Users select 2,'Ajay'
DECLARE #UserAttr table(userid int,objname varchar(100),objvalue varchar(100))
insert into #UserAttr select 1,'City','Chd'
insert into #UserAttr select 1,'phone','9646XXXX'
insert into #UserAttr select 2,'phone','8985XXXX'
select * FROM
(
select u.userid,u.username,ua.objname,ua.objvalue FROM #Users u
join #UserAttr ua on u.userid = ua.userid
)a pivot (min(a.objvalue) FOR a.objname in ([city],[phone]))p
Below is the query which you can try with or without pivot.
1. Without Pivot:-
SELECT ur.UserId,ur.UserName,ur.UserEmail,
Max(CASE WHEN ua.objName = 'city' THEN ua.ObjValue END) as city,
Max (CASE WHEN ua.ObjName = 'phone' THEN ua.ObjValue END) as Phone
FROM Users ur
JOIN UserAttribute ua ON ur.UserId = ua.UserId
GROUP BY ur.UserId,ur.UserName,ur.UserEmail
2. With Pivot :-
select * from (select us.UserId,us.UserName,us.UserEmail,ua.ObjName,ua.ObjValue from users us inner join UserAttribute ua on us.UserId=ua.UserId)t pivot
(
max(ObjValue)
For ObjName in ([city],[phone])
) as pivot_table;
Please try this query and let me know the results.

How can I order by sum of three column from different tables?

select username,
(select COUNT(OpenUser) from TIcket t with(nolock) where t.OpenUser = u.UserName and cast(t.CompletedDate as date) = cast(getdate() as date) and t.IssueClass = 58) as ServiceNote,
(select COUNT(AssignUser) from TIcket t with(nolock) where ((t.AssignUser = u.UserName and t.Status = 1) and t.IssueClass != 58)) as status1,
(select COUNT(PickUpUser) from TIcket t with(nolock) where ((t.PickUpUser = u.UserName and t.Status = 2) and t.IssueClass != 58)) as status2
from users u
where isinactive = 0
and UserLevel > -1 and First_Name != ''
and center_id = '100'
I made query for my program. And I want to order by sum of three field ServiceNote,status1,status2.
I tried to order using 'Sum',(like order by (ServiceNote,status1,status2) but it doesn't work.
Doesn't this work?
order by (serviceNote + status1 + status2)
This works in most databases, but not in SQL Server. For that, use a CTE or subquery:
with cte as (
<your query here>
)
select cte.*
from cte
order by (serviceNote + status1 + status2);

How to get Max column with group by using MS SQL?

What I want to query is "get user's last fatal logs". When I query below statement it only returns "username" and "logDate" fields but I also want to get this "logDate"'s corresponding row(I mean logid, logdata);
SELECT user.username, MAX(log.logDate) FROM user
INNER JOIN log ON user.userid = log.userid
WHERE log.logtype = 'fatal'
GROUP BY user.username
My user table;
userid username
-----------------
1 robert
2 ronaldo
log table;
logid logDate logtype userid logdata
----------------------------------------------------------
1 2016-11-28 19:37:53.000 fatal 1 data
2 2016-11-28 22:37:53.000 fatal 1 data
3 2016-11-28 12:37:53.000 fatal 2 data
I will do this using CROSS APPLY(preferred approach with proper index added to Log table)
SELECT *
FROM [USER] u
CROSS apply (SELECT TOP 1 *
FROM log l
WHERE u.userid = l.userid
AND l.logtype = 'fatal'
ORDER BY l.logDate DESC) cs
If the log table is very large then create a Non Clustered Index on Log table to improve the performance
CREATE NONCLUSTERED INDEX NIX_Log_logtype_userid
ON [log] (logtype,userid)
INCLUDE (logid,logDate,logdata)
Another approach using ROW_NUMBER
SELECT *
FROM (SELECT *,
Row_number()OVER(partition BY [USER].username ORDER BY log.logDate DESC) AS rn
FROM [USER]
INNER JOIN log
ON [USER].userid = log.userid
WHERE log.logtype = 'fatal') A
WHERE rn = 1
Another approach using ROW_NUMBER and TOP 1 with ties
SELECT TOP 1 WITH ties *
FROM [USER]
INNER JOIN log
ON [USER].userid = log.userid
WHERE log.logtype = 'fatal'
ORDER BY Row_number()OVER(partition BY [USER].username ORDER BY log.logDate DESC)
Note : All the queries result all the column from both the tables select the required columns
You can use ROW_NUMBER for this:
SELECT user.username,
log.logid, log.logtype, log.logDate, log.logdata
FROM (
SELECT user.username,
log.logid, log.logtype, log.logDate, log.logdata,
ROW_NUMBER() OVER (PARTITION BY user.username
ORDER BY log.logDate DESC) AS rn
FROM user
INNER JOIN log ON user.userid = log.userid
WHERE log.logtype = 'fatal') AS t
WHERE t.rn = 1
A quick option would be to get the max logdate in a subquery. This way, you can select any fields you need from the user table and don't have to aggregate in the outer query. The only issue with this one is that your logdate needs to not have duplicates. If it's a datetime then this isn't likely but you may have duplicates if it's just a date field. Worth checking.
SELECT
u.username
,u.logdate
,u.logid
,u.logdata
FROM user u
INNER JOIN (SELECT
userid
,MAX(logdate) MaxLog
FROM log
WHERE logtype = 'fatal'
GROUP BY userid) l
ON u.userid = l.userid
AND u.logdate = l.MaxLog
WITH MaxLogDate AS (
SELECT user.userid, MAX(log.logDate) logDate FROM user
INNER JOIN log ON user.userid = log.userid
WHERE log.logtype = 'fatal'
GROUP BY user.userid
)
SELECT log.logid, log.logDate, log.logtype, u.userid, u.username
FROM user u
JOIN MaxLogDate m ON u.userid = m.userid
JOIN log ON log.logDate = m.logDate AND log.userid = m.userid
WHERE log.logtype = 'fatal' --This line is optional, may increase the performance.

How to get amount of records of a specific ID in a database?

I want to check which users have the most records in a database. So every user has a specific Id, and that Id is used as a reference in a few tables.
There are a few tables that contain a column UserId, like the table Exams, Answers, Questions, Classes, etc. Is it possible to count all the records with a specific UserId in all those tables?
;with cte as (
select rowsCount = count(*) from A where UserId = 1
union all
select rowsCount = count(*) from B where UserId = 1
union all
select rowsCount = count(*) from C where UserId = 1
)
select sum(rowsCount) from cte
I would do it in this way:
With AllRecords AS
(
SELECT TableName = 'Exams'
FROM dbo.Exams
WHERE UserId = #YouruserID
UNION ALL
SELECT TableName = 'Answers'
FROM dbo.Answers
WHERE UserId = #YouruserID
UNION ALL
SELECT TableName = 'Questions'
FROM dbo.Questions
WHERE UserId = #YouruserID
UNION ALL
SELECT TableName = 'Classes'
FROM dbo.Classes
WHERE UserId = #YouruserID
)
SELECT COUNT(*) FROM AllRecords
The table-name is not needed if you just want the count, it's just for the case that you want to know the source.
Try like this,
SELECT Count(E.ID) + Count(A.ID) + Count(Q.ID) + Count(C.ID) AS SumofAllCount
FROM dbo.Exams E
LEFT JOIN dbo.Answers A ON A.UserId = E.UserId
LEFT JOIN dbo.Questions Q ON Q.UserId = E.UserId
LEFT JOIN dbo.Classes C ON C.UserId = E.UserId
WHERE E.UserId = #YouruserID
GROUP BY E.UserId

How to eliminate 'The multi-part identifier "" could not be bound' error?

I have this query, it's supposed to return results of non validated accounts in a database, that were created after a certain date. I keep getting this error and I'm not sure how to eliminate it. Here is the query:
select count(*) (nolock)
from dbo.[User]
where ID is not null
and UserStatusID!=2
and CreateDateTime>='5/1/2012'
and not exists (select userid from dbo.UserValidation where dbo.[User].UserID=dbo.UserValidation.UserID)
It errors out on the "where dbo.[User].UserID=dbo.UserValidation.UserID" What am I doing wrong here?
Try aliasing the tables:
select count(*) (nolock)
from dbo.[User] u
where ID is not null
and UserStatusID != 2
and CreateDateTime >= '5/1/2012'
and not exists (select uv.userid from dbo.UserValidation uv where u.UserID = uv.UserID)
Without the schema:
select count(*) (nolock)
from [User] u
where ID is not null
and UserStatusID != 2
and CreateDateTime >= '5/1/2012'
and not exists (select uv.userid from UserValidation uv where u.UserID = uv.UserID)
While doing a JOIN it's always better to explicitly qualify all the columns in query like below.
select count(u.userid)
from [User] u
where u.ID is not null
and u.UserStatusID != 2
and u.CreateDateTime >= '5/1/2012'
and not exists
(
select uv.userid
from UserValidation uv
where uv.UserID = u.UserID
)