How do I group the results by company? - sql

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

Related

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

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;

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

I want to fetch data in sequence of their branched data if exists

Hi i have data in one table as Question Table
QuestionID QuestionDescription
2 This is test
3 test is tst
4 3
6 5
17 6
18 7
19 8
20 9
5 4
and in one Table QuestionBranching Table as
QuestionBranchingID QuestionID Response NextQuestionID ParentQuestionID
1 3 True 5 3
2 3 False 6 3
7 5 True 19 3
8 5 False 20 3
9 18 True 17 18
10 18 False 4 18
So if any QuestionID exists in the QuestionBranching table then the Select Join query should fetch data in that sequence order. for ex.:
If QuestionID exists in QuestionBranching Table then NextQuestionID will be next in the sequence.
and If not then normal flow.
So the desired result i am looking for is :
QuestionID
2
3(if it exists in QuestionBranching then NextQuestionID will be next i.e. '5')
5
6
19
20
18
17
4
Try this:
select isnull(b.NextQuestionID,q.QuestionID) as QuestionID
from Question q
left join QuestionBranching b on q.QuestionID=b.QuestionID
maybe this can help you
declare #question table (QuestionID int, QuestionDescription varchar(100))
declare #branching table (BranchingID int, QuestionID int, Response bit, NextQuestionID int)
insert into #question values (2, 'this is a test'), (3, 'test is tst'), (4, '3'), (6, '5'), (17, '6'), (18, '7'), (19, '8'), (20, '9'), (5, '4')
insert into #branching values (1, 3, 1, 5), (2, 3, 0, 6), (7, 5, 1, 19), (8, 5, 0, 20)
select t.nq
from ( select q.QuestionID, q.QuestionID as nq
from #question q
union all
select isnull((select b2.QuestionID from #branching b2 where b2.NextQuestionID = b.QuestionID), b.QuestionID) as QuestionID, b.NextQuestionID as nq
from #branching b
) t
order by t.QuestionID, t.nq

Create a table with maximum values out of 2 combined tables in SQL Server

Currently running into a problem with SQL Server (SSMS 17.4), I have combined 2 tables with different columns into 1 table, making use of the unique ID done in Abc_ID.
Table 1
Abc_ID Color Value
-----------------------
1 1
2 a -0.5
2 b 0
2 c -0.1
2 d 0
2 e 0
2 f 0
2 g 1
2 h 3
2 i -5
3 a -0.9
4 a -.023
5 a 0
5 b 7.548
5 c -0.8774
6 a 1
6 b 0.5
6 c 0
7 a 2.1
7 b -1
7 c -2.5
8 a -1.1
8 b 5
Table 2
Abc_ID ProductLine Name
----------------------------
1 prod1 INTERCEPT
2 prod1 BASE
3 prod1 RawCost
4 prod1 FEAT1
5 prod1 FEAT2
6 prod1 FEAT3
7 prod1 FEAT4
8 prod1 FEAT5
Table 1 just returns the material (Abc_ID), the color and the value, and table 2 returns the productline and the name per material.
The merged table now looks like
Abc_ID,Color, Value, Productline, name
Query:
select
ah.Abc_ID, ah.Color, ah.value, ad.ProductLine, ad.name
From
[dbo].[table1] ah
Join
[dbo].[tl_table2] ad on ah.Abc_ID = ad.Abc_ID
Now, I would like to calculate the MAX value of the color (as a material can have different colors, only 1 color per material is the most expensive)
where
(ah.Abc_ID, ah.value) in (select ah.Abc_ID, max(ah.value)
from [dbo].[table1]
group by [dbo].[table1].Abc_ID)
But that code throws an error:
An expression of non-boolean type specified in a context where a condition is expected, near ','.
What am I doing wrong here?
Expected result should be 1 max value per Abc_ID
Abc_ID Color Value ProductLine Name
------------------------------------------
1 1 prod1 INTERCEPT
2 h 3 prod1 BASE
3 a -0.9 prod1 RawCost
4 a -0.023 prod1 FEAT1
5 b 7.584 prod1 FEAT2
6 a 1 prod1 FEAT3
7 a 2.1 prod1 FEAT4
8 b 5 prod1 FEAT5
Sql Server does not supports this syntax where (ah.Abc_ID, ah.value) in
From your sample data and expected outcome this might do it for you
declare #table1 table (Abc_ID int, Color varchar(1), Value decimal(16,2))
declare #table2 table (Abc_ID int, ProductLine varchar(10), Name varchar(10))
insert into #table1 (Abc_ID, Color, Value)
values (1, null, 1), (2, 'a', -0.5), (2, 'b', 0), (2, 'c', -0.1), (2, 'd', 0), (2, 'e', 0), (2, 'f', 0), (2, 'g', 1), (2, 'h', 3),
(2, 'i', -5), (3, 'a', -0.9), (4, 'a', -0.023), (5, 'a', 0), (5, 'b', 7.548), (5, 'c', -0.8774), (6, 'a', 1), (6, 'b', 0.5),
(6, 'c', 0), (7, 'a', 2.1), (7, 'b', -1), (7, 'c', -2.5), (8, 'a', -1.1), (8, 'b', 5)
insert into #table2 (Abc_ID, ProductLine, Name)
values (1, 'prod1', 'INTERCEPT'), (2, 'prod1', 'BASE'), (3, 'prod1', 'RawCost'), (4, 'prod1', 'FEAT1'),
(5, 'prod1', 'FEAT2'), (6, 'prod1', 'FEAT3'), (7, 'prod1', 'FEAT4'), (8, 'prod1', 'FEAT5 ')
select ah.Abc_ID,
(select top 1 ah2.Color from #table1 ah2 where ah2.Abc_ID = ah.Abc_ID order by ah2.Value desc) as Color,
max(Value) as Value,
ad.ProductLine,
ad.Name
from #table1 ah
left join #table2 ad on ah.Abc_ID = ad.Abc_ID
group by ah.Abc_ID, ad.ProductLine, ad.Name
This produces this result :
Abc_ID Color Value ProductLine Name
------ ----- ----- ----------- ----
1 null 1 prod1 INTERCEPT
2 h 3 prod1 BASE
3 a -0,9 prod1 RawCost
4 a -0,023 prod1 FEAT1
5 b 7,548 prod1 FEAT2
6 a 1 prod1 FEAT3
7 a 2,1 prod1 FEAT4
8 b 5 prod1 FEAT5
You can also test it yourself and fiddle with this here http://sqlfiddle.com/#!18/a90f0/1
SQL Server doesn't support multiple columns in an IN filter. You should use EXISTS instead.
Change
where
(ah.Abc_ID, ah.value) in (select ah.Abc_ID, max(ah.value)
from [dbo].[table1]
group by [dbo].[table1].Abc_ID)
for
where
EXISTS (
select
'there is a match'
from
[dbo].[table1] AS T
group by
T.Abc_ID
HAVING
T.Abc_ID = ah.Abc_ID AND
max(T.value) = ah.value)

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