Sub Query having group by and count - sql

tbl_Offer
OFID bigint
Offer_Text text
OFID Offer_Text
------- ----------
1014 Test1
1015 Test2
tbl_TransactionDishout
offerNo TerminalID Created
---------------------------------
1014 170924690436418 2010-05-25 12:51:59.547
tblVTSettings
gid mid tid
-----------------------
50 153 119600317313328
104 158 160064024922223
76 162 256674529511898
1111 148 123909123909123
These are the three tables.
Now I want the information of all deals (offers) separated by schools (look gid where TerminalID in (50,76,104)).
These are the three schools: (50,76,104)
The o/p should have these fields:
OfferID(OFID), School the offer is for, Offer_Text, Number of time the offer is.
The query may be somehow like this:
SELECT OFID, Offer_Text,
Counter =
(
SELECT COUNT(*) FROM dbo.tbl_TransactionDishout t
WHERE t.OfferNo = CAST(OFID AS NVARCHAR(30))
and t.TerminalID in
(select TID from tblVTSettings where gid in (50,76,104))
)
FROM dbo.tbl_Offer
Where EXISTS (SELECT * FROM dbo.tbl_TransactionDishout
WHERE OfferNo = CAST(OFID AS NVARCHAR(30)))

Please try this.
SELECT to.OFID
,ts.gid AS 'School the offer is for'
,to.Offer_Text
,COUNT(to.OFID) AS 'Number of time the offer is'
FROM tbl_Offer to
JOIN tbl_TransactionDishout tt
ON to.OFID = tt.offerNo
JOIN tblVTSettings ts
ON ts.tid = tt.TerminalID

Try:
SELECT o.OFID,
s.gid,
o.Offer_Text,
count(*) over (partition by o.OFID) number_schools,
count(*) over (partition by s.gid) number_offers
FROM tbl_Offer o
JOIN tbl_TransactionDishout d ON o.OFID = d.offerNo
JOIN tblVTSettings s ON s.tid = d.TerminalID

Related

SQL Server cross-table join

For each AVI there can have multiple AAIs. What I want to do is find the first non-null UserID for each AVI sorted by AAI in ascending order. I then want to get the username of that user id from the user table.
So in the example below, AVI 165 would return William. i.e. it would have sorted by AAI, ignored the userid associated with 415 as this is null, returned userid 58 (corresponding to AAI416) and joined this to the user table to get William.
Table: IDS
AAI AVI UserId
------------------
415 165 NULL
416 165 58
417 165 67
210 510 71
211 510 NULL
433 534 262
Table: Username
UserId UserName
----------------
1 John
58 William
33 Lucy
45 Haley
51 Rob
I've tried it with various complex lookups, and thought I had it with this fairly simple query but it doesn't cater for the null values i.e. returns null where the first AAI has a null user value.
select
u.username
from
(select
avi, min(aai) as aaid
from
IDS
group by
avi) as au
inner join
IDS as aa on aa.aai = au.aaid
inner join
"user" as u on u.userid = aa.userid
I also tried various sub-queries along these lines but they returned all results for each AAI, not just the first.
select ui.username, aa.avi
from "user" as ui
join dbo.IDS as aa
on aa.userid=
(select top 1 userid
from dbo.IDS as aa
where aa.userid = ui.userid
)
Any pointer/help would be much appreciated.
I think you just want a way to get the first. row_number() does this:
select t.*, un.*
from (select i.*,
row_number() over (partition by avi order by aai) as seqnum
from ids i
where userid is not null
) i join
username un
on i.userid = un.userid
where seqnum = 1;
Is something like this what you are looking for?
CREATE TABLE #IDS (AAI INT, AVI INT, UserID INT)
INSERT INTO #IDS VALUES (415,165,NULL),(416,165,58),(417,165,67),(210,510,71)
CREATE TABLE #Username (UserId INT, UserName VARCHAR(20))
INSERT INTO #Username VALUES (1,'JOHN'),(58,'William'), (71,'Lucy')
SELECT #Username.username,
ca.AAI,
ca.AVI,
ca.UserID
FROM #Username
CROSS APPLY
(
SELECT TOP 1
AAI,
AVI,
UserID
FROM #IDS
WHERE #IDS.UserID = #Username.UserID
ORDER BY #IDS.AAI ASC
) AS ca;
You could use a subquery to get the first non null userid per avi sorted by aai, and then join those userids to the username table. Something along these lines..
select i.avi, un.username
from username un
inner join
(select distinct avi, min(userid) over (partition by avi order by aai) userid from ids) i
on i.userid=un.userid and un.username is not null;
If duplicated data is not a concern, you could also do
select i.avi, un.username
from username un
inner join ids i on i.userid=un.userid and un.username is not null
where i.userid in (select min(userid) over (partition by avi order by aai) from ids)
You are looking for a groupwise minimum. See this post from MySQL for an explanation of groupwise maximum:
https://dev.mysql.com/doc/refman/8.0/en/example-maximum-column-group-row.html

Count specific duplicates in Oracle

Hi I have problem to count the number of employees (EmpID) with a phone number (PhoneNum) assigned also to some other employee. But only for specific organization (OrgID)
My Oracle tables looks like this:
TABLE OrgEmployees (OrgID, EmpID, ...)
TABLE PhoneNums (ID, EmpID, PhoneNum, ...)
Sample data for the specific organization:
SELECT pn.EmpID, pn.PhoneNum FROM PhoneNums pn
WHERE EmpID IN (SELECT DISTINCT EmpID FROM OrgEmployees oe
WHERE oe.OrgID = 'XY');
EmpID PhoneNum
723 963264
731 963264
973 963276
729 963276
103 963450
725 963450
722 963460
731 963460
722 963462
731 963462
427 995487
295 995487
771 123151
503 123151
721 963265
104 963266
Correct result on above set of data should be 14.
My attempts went like this:
SELECT pn.PhoneNum, count(pn.EmpID) FROM PhoneNums pn
WHERE pn.EmpID IN (SELECT oe.EmpID FROM OrgEmployees oe
WHERE oe.OrgID = 'XY')
GROUP BY pn.PhoneNum
HAVING count (*) > 1
ORDER BY pn.PhoneNum;
But how could I consider if EmpID are the same or not?
Thank you in advance
I think you want count(distinct):
SELECT pn.PhoneNum, COUNT(DISTINCT pn.EmpID)
FROM PhoneNums pn
WHERE pn.EmpID IN (SELECT oe.EmpID
FROM OrgEmployees oe
WHERE oe.OrgID = 'XY'
)
GROUP BY pn.PhoneNum
HAVING COUNT(DISTINCT pn.EmpID) > 1
ORDER BY pn.PhoneNum;
I would be more inclined to write this using JOIN rather than IN:
SELECT pn.PhoneNum, COUNT(DISTINCT pn.EmpID)
FROM PhoneNums pn JOIN
OrgEmployees oe
ON oe.OrgID = 'XY' AND pn.EmpID = oe.EmpID
GROUP BY pn.PhoneNum
HAVING COUNT(DISTINCT pn.EmpID) > 1
ORDER BY pn.PhoneNum;

Find out the last updated record in my DB using MAX in CASE statement

I have APPLICATIONSTATUSLOG_ID primary key field on my table.
In order to find out the last updated record in my DB and the MAX(APPLICATIONSTATUSLOG_ID) is presumed to be the most recent record.
I tried this code :
SELECT
MAX(CASE WHEN MAX(d.ApplicationStatusLog_ID) = d.ApplicationStatusLog_ID THEN d.ApplicationStatusID END) AS StatusID,
FROM
ApplicationStatusLog d
But I get error:
Msg 130, Level 15, State 1, Line 53 Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
My table looks like
ApplicationID - ApplicationStatusID - ApplicationStatusLogID
10000 17 100
10000 08 101
10000 10 102
10001 06 103
10001 10 104
10002 06 105
10002 07 106
My output should be:
10000 10
10001 10
10002 07
Please help me understand and resolve my problem.
If you want to just find the last updated row, given that it has max value in APPLICATIONSTATUSLOG_ID column. The query would be:
SELECT *
FROM ApplicationStatusLog
WHERE ApplicationStatusLog_ID = (SELECT MAX(ApplicationStatusLog_ID) FROM ApplicationStatusLog )
EDIT
So as you stated in comment, the query for it will be:
DECLARE #statusId INT
SELECT #statusId = STATUSID
FROM ApplicationStatusLog
WHERE ApplicationStatusLog_ID = (SELECT MAX(ApplicationStatusLog_ID) FROM ApplicationStatusLog )
EDIT 2:
The query as per your edit in question will be:
WITH C AS
(
SELECT ApplicationID,ApplicationStatusID,ApplicationStatusLogID, ROW_NUMBER() OVER (PARTITION BY ApplicationID ORDER BY ApplicationStatusLogID DESC) AS ranking
FROM ApplicationStatusLog
)
SELECT ApplicationID,ApplicationStatusID
FROM C
WHERE ranking = 1
You can join same table twice like this:
select IT.JoiningID, JT.MAXAPPLICATIONSTATUSID FROM dbo.[Table] IT
INNER JOIN (
Select JoiningID, MAX (APPLICATIONSTATUSID) MAXAPPLICATIONSTATUSID
FROM dbo.[Table]
GROUP BY JoiningID
) JT ON IT.JoiningID = JT.JoiningID
Now you have MAXAPPLICATIONSTATUSID per ID so you can write what you wand based on MAXAPPLICATIONSTATUSID.
Without full query
SELECT
x.StatusId
...
FROM <Table> a
CROSS APPLY
(
SELECT x.APPLICATIONSTATUSID as StatusId
FROM <Table> x
HAVING MAX(APPLICATIONSTATUSLOG_ID) = a.APPLICATIONSTATUSLOG_ID
GROUP BY x.APPLICATIONSTATUSID
)

SQL: Finding duplicate records based on custom criteria

I need to find duplicates based on two tables and based on custom criteria. The following determines whether it's a duplicate, and if so, show only the most recent one:
If Employee Name and all EmployeePolicy CoverageId(s) are an exact match another record, then that's considered a duplicate.
--Employee Table
EmployeeId Name Salary
543 John 54000
785 Alex 63000
435 John 75000
123 Alex 88000
333 John 67000
--EmployeePolicy Table
EmployeePolicyId EmployeeId CoverageId
1 543 8888
2 543 7777
3 785 5555
4 435 8888
5 435 7777
6 123 4444
7 333 8888
8 333 7776
For example, the duplicates in the example above are the following:
EmployeeId Name Salary
543 John 54000
435 John 75000
This is because they are the only ones that have a matching name in the Employee table as well as both have the same exact CoverageIds in the EmployeePolicy table.
Note: EmployeeId 333 also with Name = John is not a match because both of his CoverageIDs are not the same as the other John's CoverageIds.
At first I have been trying to find duplicates the old fashioned way by Grouping records and saying having count(*) > 1, but then quickly realized that it would not work because while in English my criteria defines a duplicate, in SQL the CoverageIDs are different so they are NOT considered duplicates.
By that same accord, I tried something like:
-- Create a TMP table
INSERT INTO #tmp
SELECT *
FROM Employee e join EmployeePolicy ep on e.EmpoyeeId = ep.EmployeeId
SELECT info.*
FROM
(
SELECT
tmp.*,
ROW_NUMBER() OVER(PARTITION BY tmp.Name, tmp.CoverageId ORDER BY tmp.EmployeeId DESC) AS RowNum
FROM #tmp tmp
) info
WHERE
info.RowNum = 1 AND
Again, this does not work because SQL does not see this as duplicates. Not sure how to translate my English definition of duplicate into SQL definition of duplicate.
Any help is most appreciated.
The easiest way is to concatenate the policies into a string. That, alas, is cumbersome in SQL Server. Here is a set-based approach:
with ep as (
select ep.*, count(*) over (partition by employeeid) as cnt
from employeepolicy ep
)
select ep.employeeid, ep2.employeeid
from ep join
ep ep2
on ep.employeeid < ep2.employeeid and
ep.CoverageId = ep2.CoverageId and
ep.cnt = ep2.cnt
group by ep.employeeid, ep2.employeeid, ep.cnt
having count(*) = cnt -- all match
The idea is to match the coverages for different employees. A simple criteria is that the number of coverages need to match. Then, it checks that the number of matching coverages is the actual count.
Note: This puts the employee id pairs in a single row. You can join back to the employees table to get the additional information.
I have not tested the T-SQL but I believe the following should give you the output you are looking for.
;WITH CTE_Employee
AS
(
SELECT E.[Name]
,E.[EmployeeId]
,P.[CoverageId]
,E.[Salary]
FROM Employee E
INNER JOIN EmployeePolicy P ON E.EmployeeId = P.EmployeeId
)
, CTE_DuplicateCoverage
AS
(
SELECT E.[Name]
,E.[CoverageId]
FROM CTE_Employee E
GROUP BY E.[Name], E.[CoverageId]
HAVING COUNT(*) > 1
)
SELECT E.[EmployeeId]
,E.[Name]
,MAX(E.[Salary]) AS [Salary]
FROM CTE_Employee E
INNER JOIN CTE_DuplicateCoverage D ON E.[Name] = D.[Name] AND E.[CoverageId] = D.[CoverageId]
GROUP BY E.[EmployeeId], E.[Name]
HAVING COUNT(*) > 1
ORDER BY E.[EmployeeId]

Display Mismatched Rows belonging to Same table

Student table
Student Id Student Name
1 Vijay
2 Ram
Student Detail Table
Student ID Code StudentIdentityNumber
1 Primary 143
1 Secondary 143
1 Teritary 143
2 Primary 123
2 Secondary 123
2 Teritary 126
Output required
StudentID PrimaryIdentity SecondaryIdentity TeritaryIdentity
2 123 123 126
I just want this output. The output doesnt have StudentID 1 because for him primary secondary and teritary Numbers are same. Hope it is clear
Need simple solution. Yes Code column is Only three. Static only
Please find the below query:
Hope it helps you.
WITH cte
as (SELECT StudentID , [Primary],[Secondary],[Teritary]
FROM
(SELECT
StudentID , Code, StudentIdentityNumber FROM StudentDetail) s
Pivot
( max(StudentIdentityNumber) for Code in ( [Primary],[Secondary],[Teritary]) )as pvt
)
SELECT * FROM cte where cte.[Primary]<>cte.[Secondary] or cte.[Primary]<> cte.Teritary
select pvt.StudentID,
pvt.[Primary] PrimaryIdentity,
pvt.Secondary SecondaryIdentity,
pvt.Teritary TeritaryIdentity
from StudentDetail sd
pivot
(
max(StudentIdentityNumber)
for code in ([Primary],Secondary,Teritary)
) as pvt
where pvt.[Primary] <> pvt.Secondary
or pvt.Secondary <> pvt.Teritary
SELECT sd1.Student,
sd1.StudentIdentityNumber as Primary,
sd2.StudentIdentityNumber as Secondary,
sd3.StudentIdentityNumber as Teritary
FROM StudentDetail sd1
JOIN StudentDetail sd2
ON sd1.StudentID = sd2.StudentID
AND sd1.Code = 'Primary'
AND sd2.Code = 'Secondary'
JOIN StudentDetail sd3
ON sd2.StudentID = sd3.StudentID
AND sd2.Code = 'Teritary'
WHERE sd1.Primary <> sd2.Secondary
or sd1.Primary <> sd3.Teritary