SQL. Checking condition and marking in a column - mysql

Here is my PEOPLE table where I store name, surname, DOB (date of birth) and some other data. In a new query I need to add additional column with the condition for people with the same Name & Surname combination. Here is the condition:
Go through each group of people with the same Name & Surname combinations, in additional field mark those, whose DOB is not maximum and not minimum (compared only to same Name & Surname)
If there is only 1 or 2 occurrences of same Name & Surname, mark them anyway
Here is the result of a query
Explanation:
John Doe marked as met only once
Tom Taylor marked as met only twice
Alice Smith and Bob Brown marked everywhere except records with min and max DOB
Please help to form SQL query for the desired output. Here is my understanding (guessing)
Get list of unique Name&Surname pairs, ( where occurrences >2 ??? )
For each unique pair find rows with min and max DOB (avoid them)
In a new CheckBox column mark those that are left (not extremum)

First group by name, surname to get the number of occurrences and min and max dob of each name and surname and join the results to the table.
With a CASE statement apply the conditions:
select
p.*,
case
when g.counter in (1, 2) then 'mark'
else case
when p.dob not in (g.mindob, g.maxdob) then 'mark'
end
end Checkbox
from peaople inner join (
select
name, surname,
count(*) counter,
min(dob) mindob,
max(dob) maxdob
from people
group by name, surname
) g on g.name = p.name and g.surname = p.surname

Use window functions in MySQL 8+:
select p.*,
(case when count(*) over (partition by name, surname) <= 2
then 'mark'
when row_number() over (partition by name, surname order by dob) > 1 and
row_number() over (partition by name, surname order by dob desc) > 1
then 'mark'
end) as checkbox
from people p;
Note: If there are duplicates for the earliest or latest birthdate, this only excludes one of them. If you want to exclude all of them, use rank() instead of row_number().

Related

Trouble with mysql subquery

I have a table with the following values: Name, Street,I'd , Value, Date.
I need to combine Name, Street, Id and make 2 subgroups by date. I want to compare the value in row with the same name, street and id but different date. And write only the ones with different value
Example:
Mike, Street 1 , idtag , 5 , 11.5.2022
Mike, street 1 , idtag , 10 , 10.5.2022
I want to write the difference in value with the name, street, id combination.
All the solutions I have tried take way to long
dYou could use an aggregation approach here. Assuming that you want to flag any name, street, and ID combination which have 2 or more records on different dates, you may try:
SELECT name, street, ID, MAX(val) - MIN(val) AS diff
FROM yourTable
GROUP BY name, street, ID
HAVING MIN(date) <> MAX(date);
To use this logic for a specific pair of records, whose (unique) date values are known, use this version:
SELECT name, street, ID, MAX(val) - MIN(val) AS diff
FROM yourTable
GROUP BY name, street, ID
HAVING MIN(date) = '2022-05-10' AND MAX(date) = '2022-05-11';

MySQL: Query that finds how many customer of each gender we have in each state

Write a query that finds how many customer of each gender we have in each state
select Gender, count(*) as Number_of_each_gender
from Customer_info
group by Gender;
This outputs the table I have below, which is correct but I'm missing the in each State part, any help? MySQL
Gender Number_of_each_gender
Male 4
Female 3
You add State to the query and Group By
SELECT Gender, State, COUNT(*) AS Number_of_each_gender
FROM Customer_info
GROUP BY State, Gender
ORDER BY State,Gender;

MYSQL count multiple orders without grouping

I'm trying to produce a query that shows every order AND adds an additional column which shows if the customer has previously placed an order by NAME, ADDRESS or USER_ID, without grouping results.
I've tried:
SELECT *, COUNT(`NAME`) c FROM `salesorders` GROUP BY `NAME` HAVING c > 0
This shows all customer orders, however if the customer has previously ordered before, the customers name only shows once due to the grouping.
e.g.
Name, Date, Previous_Orders
John Smith, 2019-11-28, 2
Lisa Thomas, 2019-11-20, 1
I would like it show both occurrences:
John Smith, 2019-11-28, 2
Lisa Thomas, 2019-11-20, 1
John Smith, 2019-05-07, 2
salesorders columns;
Name
User_ID
Date
Lets say the new column is Previous_Orders
For MariaDB 10.4.6 you can use COUNT() window function:
select *,
count(full_add) over (partition by full_add) Previous_Orders
from salesorders;
If the column Name is unique, then you can replace user_id with Name if you prefer.
If by Previous_Orders you mean the number of orders up to the date in the current row, then change to:
select *,
count(full_add) over (partition by full_add order by date) Previous_Orders
from salesorders;
See the demo.
You could use a join with the subquery for count group by name
SELECT s.*, t.c
FROM `salesorders` s
INNER JOIN
(SELECT name, COUNT(*) c
FROM salesorders
GROUP BY name) t ON t.name = s.name
WHERE t.c > 0

SQL query verification - simple

I am trying to write a query to find the 2nd oldest girl student in a class
DOB is date of birth as time stamp
name and gender are varchar
SELECT min(DOB)
FROM Student
WHERE DOB > (SELECT min(DOB) FROM Student where gender='girl')
Is this correct?
Or simpler:
SELECT DOB
FROM Student
WHERE gender='girl'
GROUP BY DOB
ORDER BY DOB ASC
LIMIT 1,1
Grouping by DOB means that two identical DOBs (twins?) that the next lowest is select. It can be omitted in a second identical date counts as the second oldest.
The below query will provide you the desired output
WITH T AS
(
SELECT *
DENSE_RANK() OVER (ORDER BY DOB ) AS Rnk
FROM Student
WHERE gender='girl'
)
SELECT min(DOB)
FROM T
WHERE Rnk = 2;
You can change the RNK value to get the next oldest value, say for third oldest you can use WHERE Rnk = 3
WITH myTableWithRows AS (
SELECT (ROW_NUMBER() OVER (ORDER BY Student.DOB)) as row,*
FROM Student )
SELECT * FROM myTableWithRows WHERE row = 2
I created this fake example and the query result is the following:
Or alternatively you can use this query:
Select top 1 * from (select top 2 from Student order by dob desc) order by dob desc

Simple SQL Ordering Question

If I had the following relation
Staff (staffNo(PK), fName, lName, position, sex, DOB)
How would I go about writing a query which produced a list of all details of all female staff ordered by their second name then their first name?
My guess is:
SELECT * FROM Staff ORDER BY fName ASC, lName ASC WHERE sex = 'f'
Is this correct?
Well, you can try this out to see if this is correct :)
But you should swap where predicate with order by clause, and ordering predicates as well: if you want to sort by the last name at first - you should specify last name first in the order by.
SELECT * FROM staff WHERE sex = 'F' ORDER BY lName ASC, fName ASC
You had fName and lName the wrong way round, and your ORDER BY comes after the WHERE
Try this query:
SELECT * FROM Staff WHERE sex = 'f' order by lName, fName;