How can we select distinct *, From and get only Distinct IDs? - sql

I have a small dataset that looks like this.
SELECT *
INTO Order_Table
FROM (VALUES
(1, 456, 'repair', 'House'),
(2, 456, 'paint', 'House'),
(3, 678, 'repair', 'Fence'),
(4, 789, 'repair', 'House'),
(5, 789, 'paint', 'House'),
(6, 789, 'repair', 'Fence'),
(7, 789, 'paint', 'Fence')
)
v (OrderNum, CustomerNum, OrderDesc, Structure)
SELECT *
INTO Veg_Table
FROM (VALUES
(1, '12/01/2020'),
(2, '12/02/2020'),
(3, '12/03/2020'),
(4, '12/04/2020'),
(5, '12/05/2020'),
(6, '12/06/2020'),
(7, '12/07/2020'),
(1, '12/10/2020'),
(2, '12/11/2020'),
(3, '12/12/2020')
)
v (ID, MyDate)
I have a query that looks something like this...
Select Distinct CTE.ID, *
From (
Select *
From Order_Table as Hist
Inner Join Veg_Table As Veg
On Hist.OrderNum = Veg.ID) as CTE
How can this query be modified to give only unique IDs? I always get duplicate IDs.
I also tried: Where In (Select Distinct ID From Event_View)
That didn't work either.
I want to end up with something like this.
OrderNum CustomerNum OrderDesc Structure ID MyDate
1 456 repair House 1 12/1/2020
2 456 paint House 2 12/2/2020
3 678 repair Fence 3 12/3/2020
4 789 repair House 4 12/4/2020
5 789 paint House 5 12/5/2020
6 789 repair Fence 6 12/6/2020
7 789 paint Fence 7 12/7/2020
I suppose Row_Number() Over (Partition By ID) would do it, but I was hoping for a simpler solution using 'Distinct'.

Using a regular GROUP BY and MIN appears to give you what you want.
SELECT Hist.OrderNum, Hist.CustomerNum, Hist.OrderDesc, Hist.Structure, MIN(Veg.MyDate)
FROM #Order_Table AS Hist
INNER JOIN #Veg_Table AS Veg ON Hist.OrderNum = Veg.ID
GROUP BY Hist.OrderNum, Hist.CustomerNum, Hist.OrderDesc, Hist.Structure;

Related

Only assign values to entries relevant to condition

I have the following code
with my_table (id, student, category, score)
as (values
(1, 'Alex', 'A', 11),
(2, 'Alex', 'D', 4),
(3, 'Bill', 'A', 81),
(4, 'Bill', 'B', 1),
(5, 'Bill', 'D', 22),
(6, 'Carl', 'C', 5),
(7, 'Carl', 'D', 10)
)
select
id, student, category, score,
case when
max(score) filter (where category in ('A', 'B', 'C')) over (partition by student) >
min(score) filter (where category = 'D') over (partition by student)
then 'Review'
else 'Pass'
end as result
from my_table
order by student, id
which outputs
id student category score conclusion
1 Alex A 11 Review
2 Alex D 4 Review
3 Bill A 81 Review
4 Bill B 1 Review
5 Bill D 22 Review
6 Carl C 5 Pass
7 Carl D 10 Pass
How can I edit it so only the entries where either A, B, or C are larger than D are assigned 'Review' to them. So in this case, the desired output would be:
id student category score conclusion
1 Alex A 11 Review
2 Alex D 4 Review
3 Bill A 81 Review
4 Bill B 1 Pass
5 Bill D 22 Review
6 Carl C 5 Pass
7 Carl D 10 Pass
For Bill, A>D so Review is assigned to it; B<D so Pass is assigned to it.
From your logic, you can try to use subquery to get count then compare
with my_table (id, student, category, score)
as (values
(1, 'Alex', 'A', 11),
(2, 'Alex', 'D', 4),
(3, 'Bill', 'A', 81),
(4, 'Bill', 'B', 1),
(5, 'Bill', 'D', 22),
(6, 'Carl', 'C', 5),
(7, 'Carl', 'D', 10)
)
SELECT id, student, category, score,
CASE WHEN
COUNT(*) filter (where D_Score<score) over (partition by student) = 0 OR score < D_Score
THEN 'Pass'
ELSE 'Review' END
FROM (
SELECT *,
min(score) filter (where category = 'D') over (partition by student) D_Score
FROM my_table
) t1
sqlfiddle

Select rows using group by and in each group get column values based on highest of another column value

I need to get latest field based on another field in group by
we have
Table "SchoolReview"
Id
SchoolId
Review
Point
1
1
rv1
8
2
1
rv2
7
3
2
rv3
4
4
2
rv4
7
5
3
rv5
2
6
3
rv6
8
I need to group by SchoolId and the inside group I need to get Review and Point from highest "Id" column.
I dont need "Id" coulmn but even if I get it for this solution its okay.
Result I am looking for shall look like this.
SchoolId
Review
Point
1
rv2
7
2
rv4
7
3
rv6
8
Any one experienced in MS SQL Server can help in this regard?
Using sample data from other answer
SELECT *
INTO #Data
FROM (VALUES
(1, 1, 'rv1', 8),
(2, 1, 'rv2', 7),
(3, 2, 'rv3', 4),
(4, 2, 'rv4', 7),
(5, 3, 'rv5', 2),
(6, 3, 'rv6', 8)
) v (Id, SchoolId, Review, Point)
SELECT S.SchoolId,
S.Review,
S.Point
FROM #Data S
INNER JOIN
(
SELECT Id = MAX(S1.Id),
S1.SchoolId
FROM #Data S1
GROUP BY SchoolId
) X ON X.Id = S.Id AND X.schoolId = S.SchoolId
ORDER BY X.SchoolId
;
output
You do not need to group the rows, you simply need to select the appropriate rows from the table. In this case, using ROW_NUMBER() is an option:
Table:
SELECT *
INTO Data
FROM (VALUES
(1, 1, 'rv1', 8),
(2, 1, 'rv2', 7),
(3, 2, 'rv3', 4),
(4, 2, 'rv4', 7),
(5, 3, 'rv5', 2),
(6, 3, 'rv6', 8)
) v (Id, SchoolId, Review, Point)
Statement:
SELECT SchoolId, Review, Point
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY SchoolId ORDER BY Id DESC) AS Rn
FROM Data
) t
WHERE Rn = 1
Result:
SchoolId Review Point
---------------------
1 rv2 7
2 rv4 7
3 rv6 8

How do I group the results by company?

I have the following sql fiddle:
CREATE TABLE companies (pk serial PRIMARY KEY, name text, max int);
INSERT INTO companies(name, max)
VALUES
('Company A', 3),
('Company B', 8),
('Company C', -1);
CREATE TABLE employees (pk serial PRIMARY KEY, company integer REFERENCES companies (pk),
name text, joined timestamp);
INSERT INTO employees (company, name, joined)
VALUES
(2, 'Jane', '2015-09-23 14:46:57'),
(2, 'Jack', '2015-09-23 14:46:57'),
(3, 'Frank', '2015-09-23 14:51:07'),
(2, 'Bob', '2015-09-23 14:56:11'),
(1, 'Carl', '2015-09-23 16:12:05'),
(1, 'Jason', '2015-09-23 16:15:35'),
(3, 'Fred', '2015-09-23 16:28:35'),
(2, 'Bruce', '2015-09-23 16:35:51'),
(1, 'Brian', '2015-09-23 16:36:17'),
(1, 'Ryan', '2015-09-23 16:36:22'),
(1, 'Peter', '2015-09-23 16:37:04'),
(3, 'Ed', '2015-09-23 16:37:11'),
(2, 'Jenny', '2015-09-23 16:37:15'),
(2, 'Jessica', '2015-09-24 09:52:46'),
(3, 'Anita', '2015-09-24 10:01:19'),
(3, 'Melanie', '2015-09-24 10:05:27'),
(3, 'Kathryn', '2015-09-24 10:05:29'),
(2, 'Ashely', '2015-09-24 10:19:46'),
(1, 'Valerie', '2015-09-24 14:49:05'),
(2, 'Jimmy', '2015-09-24 15:42:45'),
(3, 'Johnny', '2015-09-24 17:38:06'),
(1, 'Mick', '2015-09-25 14:49:10');
SELECT * -- choose the columns you want here
FROM (SELECT e.*, c.max,
row_number() over (partition by company order by joined desc) as rank
FROM employees e JOIN
companies c
on e.company = c.pk
) e
WHERE rank <= max or max = -1
This gives:
pk company name joined max rank
22 1 Mick 2015-09-25T14:49:10Z 3 1
19 1 Valerie 2015-09-24T14:49:05Z 3 2
11 1 Peter 2015-09-23T16:37:04Z 3 3
20 2 Jimmy 2015-09-24T15:42:45Z 8 1
18 2 Ashely 2015-09-24T10:19:46Z 8 2
14 2 Jessica 2015-09-24T09:52:46Z 8 3
13 2 Jenny 2015-09-23T16:37:15Z 8 4
8 2 Bruce 2015-09-23T16:35:51Z 8 5
4 2 Bob 2015-09-23T14:56:11Z 8 6
1 2 Jane 2015-09-23T14:46:57Z 8 7
2 2 Jack 2015-09-23T14:46:57Z 8 8
21 3 Johnny 2015-09-24T17:38:06Z -1 1
17 3 Kathryn 2015-09-24T10:05:29Z -1 2
16 3 Melanie 2015-09-24T10:05:27Z -1 3
15 3 Anita 2015-09-24T10:01:19Z -1 4
12 3 Ed 2015-09-23T16:37:11Z -1 5
7 3 Fred 2015-09-23T16:28:35Z -1 6
3 3 Frank 2015-09-23T14:51:07Z -1 7
How do I get it so that the results are grouped by company? e.g. I'd like 3 rows (1 for each company) and then an array of the employees for each. For instance, Company A would look like:
1 [{"name": "Mick", "joined": "2015-09-25T14:49:10Z", "rank": 1},{"name": "Valerie", "joined": "2015-09-24T14:49:05Z", "rank": 2},{"name": "Peter", "joined": "2015-09-23T16:37:04Z", "rank": 3}]
I have been trying various GROUP By statements and keep running into varous errors where the sql is invalid, etc.
Your sample output looks a bit like a JSON array (however, not a valid JSON value), so maybe you are looking for something like this:
select c.pk, jsonb_agg(to_jsonb(e))
from employees e
join companies c on e.company = c.pk
group by c.pk;
To get the three "most recent" employees you can use:
select c.pk, jsonb_agg(e3.emp)
from (
select company,
to_jsonb(e) as emp,
row_number() over (partition by company order by joined desc) as rn
from employees e
) e3
join companies c on e.company = c.pk
where e3.rn <= 3;
Online Example: https://rextester.com/RPSI96409

T-SQL Join with "max" filter

I'm using SQL Server 2014.
I'd like the following to give me no duplicate phone ID's or numbers:
WITH Phones as
(
SELECT * FROM (VALUES
(1,'602 600 8000'),
(2,'602 600 8001'),
(3,'602 600 8002')
) AS Vict_t (Id,Number)
), InvoicePhones as
(
SELECT * FROM (VALUES
(10, 1, 100, 'Alpha'),
(11, 1, 101, 'Bravo'),
(12, 1, 102, 'Charlie'),
(13, 2, 103, 'Alpha'),
(14, 2, 104, 'Bravo'),
(15, 2, 105, 'Charlie'),
(16, 3, 106, 'Alpha'),
(17, 3, 107, 'Bravo'),
(18, 3, 108, 'Charlie')
) as ip_t (Id,PhoneId,VoiceId, Name)
), Voices as
(
SELECT * FROM (VALUES
(100, '201701'),
(101, '201702'),
(102, '201703'),
(103, '201704'),
(104, '201705'),
(105, '201706'),
(106, '201708'),
(107, '201709'),
(108, '201710')
) AS Voices_t (Id,BillingCycle)
)
SELECT P.Id PhoneId, P.Number, IP.Name
FROM Phones P
LEFT JOIN InvoicePhones IP on IP.PhoneId = P.Id and IP.VoiceId =
(
select TOP 1 id
from Voices V
where V.Id = IP.VoiceId
order by V.BillingCycle desc
)
I cannot understand why the sub-select is not eliminating the duplicates.
What I'm receiving is this:
1 602 600 8000 Alpha
1 602 600 8000 Bravo
1 602 600 8000 Charlie
2 602 600 8001 Alpha
2 602 600 8001 Bravo
2 602 600 8001 Charlie
3 602 600 8002 Alpha
3 602 600 8002 Bravo
3 602 600 8002 Charlie
What I'm expecting is this:
1 602 600 8000 Charlie
2 602 600 8001 Charlie
3 602 600 8002 Charlie
This example uses simple integer ID's, but the real tables I'm working with are using uniqueidentifier. Thus the answer I need must take that into account.
I tried both versions of this accepted answer, but it doesn't work for me.
What am I missing?
Update
In addition to the answer I chose, I realized another way to solve this problem is as follows:
SELECT P.Id PhoneId, P.Number, IP.Name
FROM Phones P
LEFT JOIN InvoicePhones IP on IP.PhoneId = P.Id and IP.VoiceId =
(
select TOP 1 V.Id
from Voices V
INNER JOIN InvoicePhones IPS ON IPS.VoiceId = V.Id
WHERE P.Id = IPS.PhoneId
order by V.BillingCycle desc
)
I'm curious if they can also be solved with an OUTER APPLY, as mentioned in this other SO post
Looks like you need use ROW_NUMBER() to get the latest ID, but the final logic or the need for the third table isnt clear.
SQL DEMO
), filter as (
SELECT P.Id PhoneId, P.Number, IP.Name, IP.VoiceId,
ROW_NUMBER() OVER (PARTITION BY P.Id ORDER BY VoiceID DESC) as rn
FROM Phones P
LEFT JOIN InvoicePhones IP on IP.PhoneId = P.Id
)
SELECT *
FROM filter
WHERE rn = 1
OUTPUT
To include the third table:
SQL DEMO
), filter as (
SELECT P.Id PhoneId, P.Number, IP.Name, IP.VoiceId, V.*,
ROW_NUMBER() OVER (PARTITION BY P.Id ORDER BY BillingCycle DESC) as rn
FROM Phones P
LEFT JOIN InvoicePhones IP on IP.PhoneId = P.Id
LEFT JOIN Voices V on V.Id = IP.VoiceId
)
SELECT *
FROM filter
WHERE rn = 1
OUTPUT
I'm not sure what you want. But you have this condition:
IP.VoiceId = (select TOP 1 id
from Voices V
where V.Id = IP.VoiceId
order by V.BillingCycle desc
)
The correlation clause is V.id = IP.VoiceId. The equality comparison is -- essentially -- IP.VoiceId = V.id. They are the same. As long as there is at least one matching record in Voices, then the IP record passes the test. With your data, all IP records pass the test.
I'm not sure what you are really trying to accomplish. If you want only one row per phone, then I would be thinking EXISTS or IN.
The simplest way to get the results you want is:
select p.*
from phones p;
I suspect that you want more sophisticated logic, however.
;WITH Phones as
(
SELECT * FROM (VALUES
(1,'602 600 8000'),
(2,'602 600 8001'),
(3,'602 600 8002')
) AS Vict_t (Id,Number)
), InvoicePhones as
(
SELECT * FROM (VALUES
(10, 1, 100, 'Alpha'),
(11, 1, 101, 'Bravo'),
(12, 1, 102, 'Charlie'),
(13, 2, 103, 'Alpha'),
(14, 2, 104, 'Bravo'),
(15, 2, 105, 'Charlie'),
(16, 3, 106, 'Alpha'),
(17, 3, 107, 'Bravo'),
(18, 3, 108, 'Charlie')
) as ip_t (Id,PhoneId,VoiceId, Name)
), Voices as
(
SELECT * FROM (VALUES
(100, '201701'),
(101, '201702'),
(102, '201703'),
(103, '201704'),
(104, '201705'),
(105, '201706'),
(106, '201708'),
(107, '201709'),
(108, '201710')
) AS Voices_t (Id,BillingCycle)
)
,Expected
AS
(
SELECT P.Id PhoneId, P.Number, IP.Name
FROM Phones P
LEFT JOIN InvoicePhones IP on IP.PhoneId = P.Id and IP.VoiceId =
(
SELECT TOP 1 id
FROM Voices V
WHERE V.Id = IP.VoiceId
ORDER BY V.BillingCycle desc
)
)
SELECT PhoneId,Number,Name From
(
SELECT *,ROW_NUMBER()OVER(PARTITION BY Phoneid,Number ORDER BY Phoneid)AS Seq
FROM Expected
)DT
WHERE DT.Seq=3
OutPut
PhoneId Number Name
------------------------------
1 602 600 8000 Charlie
2 602 600 8001 Charlie
3 602 600 8002 Charlie

Find MisMatch rows in same table in SQL Server

StudentID StudentID NO
1 111
1 211
1 111
2 444
2 444
2 444
5 555
5 555
5 NULL
6 66
6 66
6 66
6 66
Output
1
5
The output is 1 and 5 because they have different studentIDnos wheareas 2 and 6 have same studentIDnos. We should take care null also. Consider 5
I need a SQL server Query to get this output
You can achieve this with a group by and having clause like this:
SELECT studentID
FROM YourTable
GROUP BY studentID
HAVING count(distinct isnull(studentID_NO,1)) > 1
It will return every students that have more then 1 studentID_NO
INSERT INTO #Table1
(StudentID, StudentIDNO)
VALUES
(1, '111'),
(1, '211'),
(1, '111'),
(2, '444'),
(2, '444'),
(2, '444'),
(5, '555'),
(5, '555'),
(5, NULL),
(6, '66'),
(6, '66'),
(6, '66'),
(6, '66')
;
Select T.StudentID from (
select StudentID, StudentIDNO from #Table1
GRoup by StudentID, StudentIDNO)T
GROUP BY T.StudentID
HAVING COUNT(T.StudentID) > 1
One way:
select StudentID from T
group by StudentID
having count(distinct isnull([StudentID NO], -1)) > 1
Assuming -1 is not going to appear