sql query to order the data - sql

I want to order the data in column for a table in one order that is i am having a table Person having age like
age
12
14
13
14
45
12
45
23
12
23
12
I want to group all the similar ages one after other.How to do this?I have tried using group by
select age from person group by age.This is not working for me.

SELECT age FROM Person ORDER BY age

Try this:
SELECT * FROM Person ORDER BY age

In MySQL, you can use GROUP BY without aggregating columns but in oracle you can't. Try it using DISTINCT so it will only select unique values.
SELECT DISTINCT age
FROM Person
Order by age ASC

I thought you want to join tables, in order to do that you have the following alternatives:
1) simple join with distinct/unique
select distinct person.name, age.age
from person, age
Where Person.Age = Age.Age
order by age.age
Result:
person_5 12
person_3 14
person_1 23
person_4 23
person_2 45
2) right outer join
Select Distinct Person.Name, Age.Age
from person right outer join age
on Person.Age = Age.Age
order by age.age
Result:
person_5 12
null 13
person_3 14
person_1 23
person_4 23
person_2 45
3) left outer join
Select Distinct Person.Name, Age.Age
from person left outer join age
On Person.Age = Age.Age
order by age.age
Result:
person_5 12
person_3 14
person_1 23
person_4 23
person_2 45
The source tables:
Person table(person and age column):
person_1 23
person_2 45
person_3 14
person_4 23
person_5 12
Age table (age column only):
12
14
13
14
45
12
45
23
12
23
12

Related

SQL JOIN return only the first match

I think this is a basic question, but I couldn’t figure it out. I am new to this so please bear with me.
I am analyzing players data from the FIFA game, and I want to get a table with the highest rating of each individual player and the earliest age when that happened.
This is an example of the data:
id
name
position
rating
age
1
James
RW
70
20
1
James
RW
71
21
2
Frank
CB
73
23
2
Frank
CB
73
24
3
Miles
CM
75
27
3
Miles
CM
74
28
This is what the query should return:
id
name
position
rating
age
1
James
RW
71
21
2
Frank
CB
73
23
3
Miles
CM
75
27
I thought I could first get the highest overall for each player, and then do a JOIN to get the age, but that gives the other years a player had the same highest rating.
id
name
position
rating
age
1
James
RW
71
21
2
Frank
CB
73
23
2
Frank
CB
73
24
3
Miles
CM
75
27
Thank you,
One approach uses ROW_NUMBER with QUALIFY:
SELECT *
FROM yourTable
WHERE true
QUALIFY ROW_NUMBER() OVER (PARTITION BY id ORDER BY rating DESC, age) = 1;
Try this one (could be a bit faster):
with mytable as (
select 1 as id, "James" as name, "RW" as position, 70 as rating, 20 as age union all
select 1, "James", "RW", 71, 21 union all
select 2, "Frank", "CB", 73, 23 union all
select 2, "Frank", "CB", 73, 24 union all
select 3, "Miles", "CM", 75, 27 union all
select 3, "Miles", "CM", 74, 28
)
select array_agg(t order by rating desc, age asc limit 1)[OFFSET(0)].*,
from mytable as t
group by t.id
Try this one too if you want. I think it's what you need.
select p1.id,
p1.name,
p1.pos,
max(p1.rating),
p1.age
from players p1
join (select name, min(age) min_age
from players
group by 1) p2 on p1.name = p2.name and p1.age = p2.min_age
group by p1.id, p1.name, p1.pos, p1.age

How to join two tables and count records SQL

table 1 is maintable_KQPPJ : contains GroupID, Year, Name, VendorID. This table contains multiple records with the same GroupID
table 2 is cb_vendorinformation: contains GroupID and CompanyName
I would like to join both tables on GroupID. The output should only have GroupID, CompanyName, and Count. The Count is the distinct count of GroupID in maintable_KQPPJ.
I have the following code but it doesn't really give me the output I'm looking for.
SELECT maintable_KQPPJ.GROUPID, cb_vendorinformation.CompanyName, count(distinct maintable_KQPPJ.GROUPID)
FROM maintable_KQPPJ
JOIN cb_vendorinformation ON maintable_KQPPJ.GROUPID=cb_vendorinformation.GROUPID
maintable_KQPPJ:
GroupID Year VendorID Name
26 2019 9999 John
26 2020 2345 Jane
6 2018 3244 Jack
36 2021 3245 Jill
cb_vendorinformation:
GroupID CompanyName
26 Walmart
6 Target
36 Kroger
The output should look like
GroupID CompanyName Count
26 Walmart 2
6 Target 1
36 Kroger 1
You need group by and count(*)
SELECT maintable_KQPPJ.GROUPID
, cb_vendorinformation.CompanyName
, count(*)
FROM maintable_KQPPJ
JOIN cb_vendorinformation ON maintable_KQPPJ.GROUPID=cb_vendorinformation.GROUPID
GROUP BY maintable_KQPPJ.GROUPID
, cb_vendorinformation.CompanyName

ORACLE DB query - maximum stipend in faculty

So, i have an task in uni to get max stipend in each faculty from a table with stipends.
Faculty table is:
ID_FACULTY FACULTY_NAME DEAN TELEPHON
---------- ------------------------------ -------------------- --------
10 Informacijas tehnologiju Vitols 63023095
11 Lauksaimniecibas Gaile 63022584
12 Tehniska Dukulis 53020762
13 Partikas tehnologijas Sabovics 63021075
Money table is:
ID_PAYOUT STUDENT_ID PAYOUT_DA STIPEND COMPENSATION
---------- ---------- --------- ---------- ------------
100 1 24-SEP-20 45.25 15
101 7 20-SEP-20 149.99 0
102 3 18-SEP-20 100 0
103 17 02-SEP-20 90.85 20
104 9 03-SEP-20 85 20
105 19 09-SEP-20 70.75 0
106 25 15-SEP-20 55 15
107 17 17-SEP-20 105.54 0
108 15 22-SEP-20 94 0
109 27 28-SEP-20 100 20
And the student table is:
ID_STUDENT SURNAME NAME COURSE_YEAR FACULTY_ID BIRTHDATE
---------- ------------------------- -------------------- ----------- ---------- ---------
1 Lapa Juris 4 13 27-SEP-96
3 Vilkauss Fredis 2 10 17-MAY-99
5 Karlsone Rasa 1 11 13-MAR-00
7 Grozitis Guntars 3 12 16-APR-97
9 Sonciks Jurgis 2 10 17-MAR-99
11 Berzajs Olafs 3 10 14-FEB-97
13 Vike Ilvija 2 13 14-MAY-99
15 Baure Inga 3 11 12-APR-97
17 Viskers Zigmunds 2 13 15-AUG-99
19 Talmanis Harijs 3 13 15-JUL-97
21 Livmanis Indulis 1 10 19-JAN-00
23 Shaveja Uva 2 13 18-FEB-98
25 Lacis Guntis 4 10 17-SEP-96
27 Liepa Guna 4 11 18-AUG-96
29 Klava Juris 2 10 19-MAY-98
I have tried many variations of queries, i think that I even tried all the possible combinations of joins, but i cannot achieve the neccessary result.
One of my queries looked like this:
SQL> SELECT ROW_NUMBER() OVER (ORDER BY surname) "Nr.",
f.faculty_name,
s.surname,
s.name,
MAX(m.stipend)
FROM faculty f, student s INNER JOIN money m ON s.id_student = m.student_id
WHERE s.faculty_id = f.id_faculty
GROUP BY f.faculty_name, s.surname, s.name
ORDER BY s.surname;
Which returned me the following result:
Nr. FACULTY_NAME SURNAME NAME MAX(M.STIPEND)
---------- ------------------------------ ------------------------- -------------------- --------------
1 Lauksaimniecibas Baure Inga 94
2 Tehniska Grozitis Guntars 149.99
3 Informacijas tehnologiju Lacis Guntis 55
4 Partikas tehnologijas Lapa Juris 45.25
5 Lauksaimniecibas Liepa Guna 100
6 Informacijas tehnologiju Sonciks Jurgis 85
7 Partikas tehnologijas Talmanis Harijs 70.75
8 Informacijas tehnologiju Vilkauss Fredis 100
9 Partikas tehnologijas Viskers Zigmunds 105.54
9 rows selected.
So the goal of this task is to retrieve the maximum amount of stipend granted to a student in a certain faculty.
Can someone please tell what am I doing wrong here?
Just max amount per faculty:
SELECT
f.faculty_name,
MAX(m.stipend)
FROM
faculty f
INNER JOIN student s ON s.faculty_id = f.id_faculty
INNER JOIN money m ON s.id_student = m.student_id
GROUP BY f.faculty_name
Max amount and all other details too:
SELECT * FROM
(
SELECT
ROW_NUMBER() OVER (PARTITION BY f.faculty_name ORDER BY m.stipend desc) rn,
f.*,
s.*,
m.*
FROM
faculty f
INNER JOIN student s ON s.faculty_id = f.id_faculty
INNER JOIN money m ON s.id_student = m.student_id
) x
WHERE x.rn = 1
Points of note:
Do not use old style joins; if you ever write one table_name, other_table_name in a FROM block, you're using old style joins. Don't do it; they became bad news about 30 years ago
When you have a max-n-per-group, you specify how finely detailed the group is. If you GROUP BY s.first_name, s.last_name, f.faculty_name then your groups are "every unique combination of firstname/lastname/faculty, so the only way you'll get multiple items in your group is if there are two John Smiths in Mathematics. If the group is to be the whole of mathematics, then the faculty name (and anything else that is uniquely related 1:1 to it, like the faculty ID) is all that you can put in your group. Anything not in a group must be in an aggregation, like MAX
When you want other details too, you either group and max the data and then join this groupmaxed data back to the original data to use it as a filter, or you use an approach like here where you use a row_number or rank, with a partition (which is like an autojoined grouped summary). There is no group here; the row numbering acts like a group because it restarts from 1 every different faculty and proceeds incrementally as stipend decreses. This means that the highest stipend is always in row number 1.
Unlike using a groupmax that you join back to get the detail, the row_number route does not produce duplicate rows with tied-for-highest stipends

Reducing lines and readability in SQL query

I have 2 tables namely:
list_a:
ID Date pg
23 2016-11-30 sub
23 2016-12-03 sub
23 2016-12-04 sub
23 2016-12-05 sub
69 2017-07-21 Closed
69 2017-07-22 Closed
69 2017-07-23 Closed
92 2016-11-29 sub
92 2016-11-30 sub
46 2017-01-11 In
46 2017-01-12 In
46 2017-01-13 In
list_b:
ID Name
23 B
46 B
69 X
92 B
My task is to write an sql query such that I get count of each date with name 'B' and the count should be greater than 4.
So far I have written the following query which gives me the output:
SELECT date, count(Name) as CountName FROM
(
SELECT list_b.ID as Id,list_b.Name as Name,Date from list_b
inner JOIN list_a
on list_b.ID=list_a.ID
) t
where Name='B'
group by Date
Having count(Name)>4
order by count(Name) desc;
I am trying to make my query more readable and less chunkier.
Is there a better way that you can suggest to solve this problem?
Note: the above tables are snippets of the original tables!
You have a spare subquery that isn't necessary. Also a personal preference to use an alias rather than table names (on a table called t_databaseassociation this does make a big difference)
Try
SELECT date, count(name) as countname
from list_b b
inner JOIN list_a a on b.ID= a.ID
where Name='B'
group by Date
Having count(Name)>4
order by count(Name) desc;
unfortunately you can't use CTE with clause in mysql, but you can create temp table:
CREATE TEMPORARY TABLE IF NOT EXISTS t AS (
SELECT list_b.ID AS Id,list_b.Name AS Name,Date
FROM list_b
INNER JOIN list_a ON list_b.ID=list_a.ID
);
SELECT date, count(Name) AS CountName
FROM t
WHERE Name='B'
GROUP BY Date HAVING count(Name)>4
ORDER BY count(Name) DESC;
SELECT `Date`, COUNT(Name) as CountName
FROM list_a
NATURAL JOIN list_b
WHERE Name = 'B'
GROUP BY `Date`
HAVING COUNT(Name) > 4
ORDER BY CountName DESC;
SELECT
list_b.Date AS date,
count(Name) AS CountName
FROM list_b
INNER JOIN list_a ON list_b.ID=list_a.ID
WHERE list_b.Name = 'B'
GROUP BY list_b.Date HAVING count(list_b.Name) > 4
ORDER BY count(Name) DESC

How to find rows where the same column has only the same another column

Suppose following table:
Name Age Occupation
Alex 20 Student
Alex 20 Seller
Alex 20 Minister
Liza 19 Student
Liza 20 Volunteer
Liza 21 HR partner
I want to find names which have only (and only) 20 in age column. So from this table I want to get all "Alex" rows and no "Liza" rows at all.
Thanks!
You need to use Group By and Having clause. Try this way
select Name
from table
group by Name
having count(case when Age = 20 then 1 end) = count(*)
count(case when Age = 20 then 1 end) counts only when age = 20 if it is equal to total count then the name has only 20 as age.
Just one another way:
select Name
from table
group by Name
having min(Age) = 20 and max(Age) = 20
One way is using NOT IN():
SELECT Name, Age, Occupation
FROM YourTable
WHERE Age = 20
AND Name NOT IN (SELECT Name FROM YourTable WHERE Age <> 20)