ORDER BY more than one column in t-sql - sql-server

I have a table of a classroom with 3 column: Name, Class and Age. When do
Select * from students
It shows these value
Name | Class | Age
John | D | 7
Mary | A | 10
Jenny | B | 9
Peter | D | 7
I want to sort the values with these conditions
- First, Order by Age DESC
- If there are more 2 people have same age, Order by Name ASC
I use these command
Select * from students order by Age Desc, Name ASC .
but it doesn't sort Class too. Is there anyone can help me?

To sort by class first, then age, then name:
Select Name, Class, Age
FROM students
ORDER BY class ASC, Age DESC, Name ASC;
Should output:
Name | Class | Age
Mary | A | 10
Jenny | B | 9
John | D | 7
Peter | D | 7
To sort by age first, then class, then name:
Select Name, Class, Age
FROM students
ORDER BY Age DESC, class ASC, Name ASC;
Should output the same, because the data provided happens to sort the same way using this alternate criteria.
Name | Class | Age
Mary | A | 10
Jenny | B | 9
John | D | 7
Peter | D | 7

Try this Query.
First use Asc then second use Desc.
Select * from students order by Name ASC, Age Desc,

declare #tab table(Name varchar(30), Class char(1), Age int )
insert into #tab
select 'John' , 'D' , 7
union all
select 'Mary' , 'A' , 10
union all
select 'Jenny' , 'B' , 9
union all
select 'Peter' , 'D' , 7
select * from #tab order by Age desc,name asc
Name Class Age
Mary A 10
Jenny B 9
John D 7
Peter D 7

Related

How to select each first three records of two different students from same table in single query

I have a student table and want to find top three records of 2 students: Amy and Jack in a single query and it should be displayed according to descending marks order.
I tried using top in subquery but it did not work.
Table:
Name | Subject | Marks
-------|---------|-------
Tara | English | 70
Amy | Maths | 70
Jack | English | 80
Amy | Science | 80
Amy | English | 90
Jack | Maths | 30
Jack | English | 50
Tara | Maths | 60
Tara | Science | 70
Expected Output:
Amy | English | 90
Amy | Science | 80
Jack | English | 80
Amy | Maths | 70
Jack | English | 50
Jack | Maths | 30
Displaying each of their top 3 records in descending order is expected.
Try with ROW_NUMBER()-
SELECT *
FROM
(
SELECT name,
Subject,
marks,
ROW_NUMBER() OVER(
PARTITION BY name ORDER BY name,marks DESC
) RN
FROM your_table
) A
WHERE A.RN < 4;
Try using this..
; WITH CTE AS (
SELECT ROW_NUMBER() OVER (PARTITION BY NAME ORDER BY MARKS) AS SLNO,
NAME, MARKS, SUBJECT FROM TAB
)
SELECT NAME, SUBJECT, MARKS FROM CTE WHERE SLNO<4 ORDER BY MARKS DESC
You can use a window function as
SELECT Name,
Subject,
Marks
FROM(
SELECT *, ROW_NUMBER() OVER(PARTITION BY Name ORDER BY Marks DESC) RN
FROM T
) V
WHERE RN < 4
AND
Name IN ('Amy', 'Jack')
ORDER BY Marks DESC;
Which will gives you exactly the results you expected.
Demo

How to efficiently match on dates in SQL Server?

I am trying to return the first registration for a person based on the minimum registration date and then return full information. The data looks something like this:
Warehouse_ID SourceID firstName lastName firstProgramSource firstProgramName firstProgramCreatedDate totalPaid totalRegistrations
12345 1 Max Smith League Kid Hockey 2017-06-06 $100 3
12345 6 Max Smith Activity Figure Skating 2018-09-26 $35 1
The end goal is to return one row per person that looks like this:
Warehouse_ID SourceID firstName lastName firstProgramSource firstProgramName firstProgramCreatedDate totalPaid totalRegistrations
12345 1 Max Smith League Kid Hockey 2017-06-06 $135 4
So, this would aggregate the totalPaid and totalRegistrations variables based on the Warehouse_ID and would pull the rest of the information based on the min(firstProgramCreatedDate) specific to the Warehouse_ID.
This will end up in Tableau, so what I've recently tried ignores aggregating totalPaid and totalRegistrations for now (I can get that in another query pretty easily). The query I'm using seems to work, but it is taking forever to run; it seems to be going row by row for >50,000 rows, which is taking forever.
select M.*
from (
select Warehouse_ID, min(FirstProgramCreatedDate) First
from vw_FirstRegistration
group by Warehouse_ID
) B
left join vw_FirstRegistration M on B.Warehouse_ID = M.Warehouse_ID
where B.First in (M.FirstProgramCreatedDate)
order by B.Warehouse_ID
Any advice on how I can achieve my goal without this query taking an hour plus to run?
A combination of the ROW_NUMBER windowing function, plus the OVER clause on a SUM expression should perform pretty well.
Here's the query:
SELECT TOP (1) WITH TIES
v.Warehouse_ID
,v.SourceID
,v.firstName
,v.lastName
,v.firstProgramSource
,v.firstProgramName
,v.firstProgramCreatedDate
,SUM(v.totalPaid) OVER (PARTITION BY v.Warehouse_ID) AS totalPaid
,SUM(v.totalRegistrations) OVER (PARTITION BY v.Warehouse_ID) AS totalRegistrations
FROM
#vw_FirstRegistration AS v
ORDER BY
ROW_NUMBER() OVER (PARTITION BY v.Warehouse_ID
ORDER BY CASE WHEN v.firstProgramCreatedDate IS NULL THEN 1 ELSE 0 END,
v.firstProgramCreatedDate)
And here's a Rextester demo: https://rextester.com/GNOB14793
Results (I added another kid...):
+--------------+----------+-----------+----------+--------------------+------------------+-------------------------+-----------+--------------------+
| Warehouse_ID | SourceID | firstName | lastName | firstProgramSource | firstProgramName | firstProgramCreatedDate | totalPaid | totalRegistrations |
+--------------+----------+-----------+----------+--------------------+------------------+-------------------------+-----------+--------------------+
| 12345 | 1 | Max | Smith | League | Kid Hockey | 2017-06-06 | 135.00 | 4 |
| 12346 | 6 | Joe | Jones | Activity | Other Activity | 2017-09-26 | 125.00 | 4 |
+--------------+----------+-----------+----------+--------------------+------------------+-------------------------+-----------+--------------------+
EDIT: Changed the ORDER BY based on comments.
Try to use ROW_NUMBER() with PARTITIYION BY.
For more information please refer to:
https://learn.microsoft.com/en-us/sql/t-sql/functions/row-number-transact-sql?view=sql-server-2017

postgresql search text into array of text

i have a table t1
id | names
----|-------------------------
1 | {jully , alex , sarah}
2 | {bety , cate , jenifer}
3 | {adam , pit , joee}
4 | {piter , mat , andy}
so, i need rows have at least one name that start with "a"
the result i need is in the below
in row 1 : alex
in row 3 : adam
in row 4 : andy
id | names
-----|-------------------------
1 | {jully , alex , sarah}
3 | {adam , pit , joee}
4 | {piter , mat , andy}
a query like it
select * from t1 where 'a' like% any t1.name
select *
from (
select id, unnest(names) as name
from t
) s
where name like 'a%';
id | name
----+------
1 | alex
3 | adam
4 | andy
To have it aggregated:
select id, array_agg(name)
from (
select id, unnest(names) as name
from t
) s
where name like 'a%'
group by id;
id | array_agg
----+-----------
4 | {andy}
1 | {alex}
3 | {adam}
And yet another solution using unnest
select * from t1
where exists (
select * from unnest(t1.names) n
where n like 'a%')
If you have to search multiple values inside the text array. You can use this:
SELECT * FROM t1 WHERE names && ARRAY['alex', 'jully'] ;

How to fractionally split a column while doing a inner join in SQL Server

I wanted to basically split a column:
Table A has 3 columns: Id, Name, Number
Table b has 3 columns: Id, Name, School
I join on the basis of Id.
Suppose that the number is 100, the Name might have multiple schools (suppose 3), so I want to equally split 100 by 3 and do the join.
Sample Final Table
Id Name School Number
---------------------------
1 ABC A 33.33
1 ABC B 33.33
1 ABC C 33.33
You can get the count for each id using count(*) over(partition by a.Id) and divide the number by that.
test setup: rextester: http://rextester.com/JQK48793
create table a (id int, name char(3), number decimal(9,2))
insert into a
values (1,'ABC',100.0)
create table b (id int, name char(3), school char(1))
insert into b values
(1,'ABC','A')
,(1,'ABC','B')
,(1,'ABC','C')
query:
select
a.Id
, a.Name
, b.School
, Number = (a.Number+.0) / count(*) over (partition by a.Id)
from a
inner join b
on a.Id = b.Id
results:
+----+------+--------+------------------+
| Id | Name | School | Number |
+----+------+--------+------------------+
| 1 | ABC | A | 33,3333333333333 |
| 1 | ABC | B | 33,3333333333333 |
| 1 | ABC | C | 33,3333333333333 |
+----+------+--------+------------------+

Convert varchar to decimal and compare values in a query

I'd like to compare in a query between decimal values in varchar columns.
The comparison should be if maximum age is highest than the minimum age * 10 for each groupid
for example (the age column is varchar):
ID | Name | Age | GroupID
--------------------------
1 | AAA | 10.1 | 1
2 | BBB | 11 | 1
3 | CCC | 31.2 | 1
4 | DDD | 30.4 | 2
This is what I've tried to do after searching for a solution
SELECT TOP 10 * FROM Groups g
JOIN People p1 ON p1.GroupID = g.ID
JOIN People p2 ON p2.GroupID = g.ID
WHERE CONVERT(DECIMAL(8,2),ISNULL(p1.Age,0)) > (CONVERT(DECIMAL(8,2),ISNULL(p2.Age,0)) * 10)
Thanks in advance!
I think you want to use window functions for this:
select t.*
from (select t.*,
min(case when isnumeric(Age) = 1 then cast(Age as float) end) over
(partition by groupID) as minage
from table t
) t
where age > 10 * minage;
The case statement helps prevent errors in the event that age's are not numeric. Also, I figure float is a good enough data type for the age, although you can also use decimal.

Resources