Select count if column name contain and value equal to something MYSQL - mysql

Here is my table call TrainingPresence
+-------+-----------+-----------+-----------+
| Name | FootNov12 | HandNov15 | FootNov22 |
+-------+-----------+-----------+-----------+
| Clem | x | Abs | Abs |
+-------+-----------+-----------+-----------+
| Kevin | x | x | x |
+-------+-----------+-----------+-----------+
I want to select the name and the number of time when player came to the Foot training.
FootNov12 = Football Novembrre 12th
FootNov22 = Football November 22th
HandNov15 = Handball November 15th
The select query should give me :
Name | Count
Clem | 1
Kevin| 2
But I don't know how to do it
Thanks for your help.

A normalised Schema might look like this
users
user_id name
1 Clem
2 Kevin
training
user_id date sport
1 2018-11-15 Handball
1 2018-11-11 Football

Related

Mysql - Get season from current month

I have the following table of seasons:
| id | name | start_month | end_month |
------------------------------------------
| 101 | Summer | 12 | 2 |
| 102 | Winter | 6 | 8 |
| 103 | Spring | 9 | 11 |
| 104 | Fall | 3 | 5 |
I need to get the season by month. Say current month is 2 (February), I want Summer to be the output.
I can get other seasons to work by simply having the where condition start_month >= 4 and end_month <= 4. But this won't work with Summer since the season crosses into next year.
What do I have to do to handle the case of Summer?
One solution I thought was to use dates instead of month number like 1980-12-01 and use between function but it gets a bit complicated for the user end.
It'd be great if it could work with just month numbers.
You could do:
(month(d) between start_month and end_month) or
(start_month>end_month and (month(d)>=start_month or month(d)<=end_month))
See db-fiddle

SQL query that searches comma-delimited field

I have a student table which looks something like this:
id | name | school_descriptors
-------------------------------------------------------
1 | Rob | Comp Sci,Undergraduate,2020
2 | Tim | Business,MBA,2022
3 | Matt | Business,MBA,2022
4 | Jack | Law,Masters,2024
5 | Steph | Comp Sci,Masters,2022
The school_descriptors field is just one column, and stores information about the Course, Qualification and Graduation year as a comma-delimited string. (it's terribly designed and I wish it could be split up into its own fields, but it can't right now (I am not the database owner))
I want to provide an interface where teachers can quickly find students that match certain Course, Qualifications and Graduation years, and thus would like to create relevant queries.
Question 1: For example, I would like a teacher to be able to select from the UI: "Business", "MBA" and get returned students with ID 2 and 3. Specifically, an example question I have is: Find students who are in the Business Course and doing the MBA qualification:
SELECT * FROM student_table WHERE school_descriptors LIKE '%Business%' AND school_descriptors LIKE '%MBA%'
The query I have in mind is a basic LIKE query, but I can't help but think there is a more efficient query that can take advantage of the fact that the school_descriptor string is 1) always in a specific order (e.g. course, qualification, graduation), and 2) comma-delimited, and thus could be perhaps split. The table currently sits at ~5000 rows so relatively small but is expected to grow.
Related question 2: Find students who are in the Comp Sci Course and graduating after 2019:
Would it be possible to split the school_descriptors field and add a >2019 operand?
Many thanks!
In MySql you can use the function SUBSTRING_INDEX() to split the column school_descriptors.
This will work only if the positions of Course, Qualification and Graduation year are fixed.
select *,
substring_index(school_descriptors, ',', 1) Course,
substring_index(substring_index(school_descriptors, ',', 2), ',', -1) Qualification,
substring_index(school_descriptors, ',', -1) Graduation
from student_table
See the demo.
Results:
> id | name | school_descriptors | Course | Qualification | Graduation
> -: | :---- | :-------------------------- | :------- | :------------ | :---------
> 1 | Rob | Comp Sci,Undergraduate,2020 | Comp Sci | Undergraduate | 2020
> 2 | Tim | Business,MBA,2022 | Business | MBA | 2022
> 3 | Matt | Business,MBA,2022 | Business | MBA | 2022
> 4 | Jack | Law,Masters,2024 | Law | Masters | 2024
> 5 | Steph | Comp Sci,Masters,2022 | Comp Sci | Masters | 2022
select id, name,
substring_index(school_descriptors,',',1) as course,
substring_index(substring(school_descriptors,length(substring_index(school_descriptors,',',1))+2,200),',',1) as Qualifications,
substring_index(school_descriptors,',',-1) as year
from student;
output:
+------+-------+----------+----------------+------+
| id | name | course | Qualifications | year |
+------+-------+----------+----------------+------+
| 1 | Rob | Comp Sci | Undergraduate | 2020 |
| 2 | Tim | Business | MBA | 2022 |
| 3 | Matt | Business | MBA | 2022 |
| 4 | Jack | Law | Masters | 2024 |
| 5 | Steph | Comp Sci | Masters | 2022 |
+------+-------+----------+----------------+------+
A link to the docs, in case you want to know about SUBSTRING_INDEX()
Answer 1:
SELECT * FROM student_table WHERE school_descriptors REGEXP ['Business','MBA']
By using this query you can get all the records that are having Business OR MBA.
If you want to select only Business, MBA you can try like this
SELECT * FROM student_table WHERE school_descriptors LIKE '%Business,MBA%'
Answer 2:
SELECT *
FROM student
WHERE
SUBSTRING_INDEX(SUBSTRING_INDEX(school_descriptors , ',', 1), ',', -1)='Comp Sci'
AND
SUBSTRING_INDEX(SUBSTRING_INDEX(school_descriptors , ',', 3), ',', -1)> 2019;

Mysql query for counting days in some season by date range

So, Im trying to make a query that will count how many days belong in different seasons. Its for site that's about booking apartments and it can have multiple seasons one after another. For example:
| Season_id | From | Till |
| 1 | 2015-09-01 | 2015-09-30 |
| 2 | 2015-09-30 | 2015-10-20 |
| 3 | 2015-10-30 | 2015-12-30 |
So when someone is searching to book for date ex.:
2015-09-25 - 2015-10-10.
I want to get result like:
Seasons: 1, 2
Count days: 5, 10
Is it possible to do that with one query or it must be multiple??
Thank you in advance.

SQL select default value when there is no such value

I have following tables in DB.
ACCOUNT TABLE
User_id| first_name | last_name | age |
_______|_____________|____________|_________|
1 | LeBron | James | 28 |
2 | Kobe | Bryent | 29 |
3 | Kevin | Durant | 30 |
4 | Jim | Jones | 31 |
5 | Paul | Pierce | 32 |
6 | Jeremy | Lin | 33 |
USER_BOOKMARK TABLE
User_id| Bookmarked_user_id
_______|____________________
1 | 2
1 | 3
1 | 4
2 | 1
2 | 4
3 | 1
5 | 6
I want to select user's information from ACCOUNT table and also whether that person is in my Bookmark list
ex) Lebron James wants to know Jeremy Lin's information and whether Jeremy is in he's bookmark lists.
Desired results =>
User_id| first_name | last_name | age | isBookmarked |
_______|_____________|____________|_________|______________|
6 | Jeremy | Lin | 33 | 0 | =>0 means no.
*It must return only one row.
*If user is on my bookmark list, value of isBookmarked is my user_id.
What I tried =>
SELECT ACCOUNT.user_id, ACCOUNT.firstname, ACCOUNT.lastname, coalesce(User_Bookmark.user_id, 0) as isBookmarked
FROM Account LEFT OUTER JOIN User_Bookmark ON Account.user_id = User_Bookmark.Bookmarked_user_id
WHERE Account.user_id=6 AND User_Bookmark.user_id=1
But this query returns zero rows... since I'm not an expert on sql, I assume that I'm missing something. Can anyone help me?
The User_Bookmark.user_id = 1 test is filtering out the non-matching rows, because that column will be NULL when there's no match. When doing a LEFT JOIN, you have to put conditions on the second table into the ON clause rather than WHEN.
SELECT ACCOUNT.user_id, ACCOUNT.firstname, ACCOUNT.lastname, coalesce(User_Bookmark.user_id, 0) as isBookmarked
FROM Account
LEFT OUTER JOIN User_Bookmark
ON Account.user_id = User_Bookmark.Bookmarked_user_id AND User_Bookmark.user_id=1
WHERE Account.user_id=6

MySQL complex date calculation in inner join

I am reading the MySql tutorial in the docs and have the following tables and SQL statements:
Event table:
+----------+------------+----------+------------------------------+
| name | date | type | remark |
+----------+------------+----------+------------------------------+
| Fluffy | 1995-05-15 | litter | 4 kittens, 3 females, 1 male |
| Buffy | 1993-06-23 | litter | 5 puppies, 2 female, 3 male |
| Buffy | 1994-06-19 | litter | 3 puppies, 3 female |
| Chirpy | 1999-03-21 | vet | needed beak streightened |
| Slim | 1997-08-03 | vet | broken rib |
| Bowser | 1991-10-12 | kennel | NULL |
| Fang | 1991-10-12 | kennel | NULL |
| Fang | 1998-08-28 | birthday | Gave him new chew toy |
| Claws | 1998-03-17 | birthday | Gave him a flea collar |
| Whistler | 1998-12-09 | birthday | First birthday |
+----------+------------+----------+------------------------------+
Pet table:
+----------+--------+---------+------+------------+------------+
| name | owner | species | sex | birth | death |
+----------+--------+---------+------+------------+------------+
| Fluffy | Harold | cat | f | 1993-02-04 | NULL |
| Claws | Gwen | cat | m | 1994-03-17 | NULL |
| Buffy | Harold | dog | f | 1989-05-13 | NULL |
| Fang | Benny | dog | m | 1990-08-27 | NULL |
| Bowser | Diane | dog | m | 1989-03-31 | 1995-07-29 |
| Chirpy | Gwen | bird | f | 1998-09-11 | NULL |
| Whistler | Gwen | bird | NULL | 1997-12-09 | NULL |
| Slim | Benny | snake | m | 1996-04-29 | NULL |
| Puffball | Diane | hamster | f | 1999-03-30 | NULL |
| Jenny | Robert | dog | f | 2004-01-01 | 2014-05-04 |
+----------+--------+---------+------+------------+------------+
SQL:
select pet.name,
( YEAR(date) - YEAR(birth) ) - ( RIGHT(date,5) < RIGHT(birth,5) ) AS age, remark
from pet inner join event
on pet.name = event.name
where event.type = 'litter';
I understand the SQL statement except for this one:
( YEAR(date) - YEAR(birth) ) - ( RIGHT(date,5) < RIGHT(birth,5) )
A step by step explanation would greatly help. I know that the YEAR() function is used to extract the year from a date.
As you've mentioned YEAR() gets the year from the date.
We will use Fluffy as an example with birth = 1993-02-04 and date = 1995-05-15
Step 1:
Subtract the extracted year from both dates ( YEAR(date) - YEAR(birth) )
You now have 1995 - 1993 which is equal to 2
Step 2:
( RIGHT(date,5) < RIGHT(birth,5) ) this will actually read the date and birth string 5 paces from right to left, so if you perform RIGHT(date,5) you will get the value 0, and if you perform RIGHT(birth,5) you will also get a value of 0.
Step 3:
Now we get on to the < operator, this returns a boolean value of 1 or 0 if it satisfies the condition. Since 0 = 0, the statement is false, so it will return to 0.
The whole function actually checks if the day part of your date is less than the day on your birthdate which will determine if you have a sort of remaining days before a whole year. And if you do, it will return 1 which will be subtracted from the current year - year operation you performed earlier.
But in our case, since the < will return 0, we can definitely say that Fluffy's age is 2 - 0, which is 2.
If, however, Fluffy's birthdate is say, 1993-12-04, this will yield a 1 value for the < operation meaning that the year is not yet complete which will bring a result of 2 - 1, which is 1.
Sorry if its a bit messy.
If you were born in 1980 and I know that right now it's 2015, then I I can almost compute your age by computing YEAR(date) - YEAR(birth) = 2015 - 1980 = 35. The sticking point is that your birthday might not have happened yet. So how can I tell if your birthday has happened? Lets say you were born on July 20, 1980. Then in MySQL date format your birthday would look like 2015-06-20. If I look at the last 5 characters of your birthday, the right-most 5 characters, or RIGHT(birth, 5) I'd get 06-20. If the the last 5 characters of today's date, 06-07 is less than the last 5 characters of your birthday then your birthday hasn't happened yet. Here, by "less than" we mean only that it would "sort before" in normal string order. So, if RIGHT(date, 5) < RIGHT(birth, 5) then your birthday hasn't happened yet. And, luckily, MySQL treats a "true" as the number 1 and a "false" as the number 0. So, the above will subtract 1 from our date computation only if your birthday hasn't happened yet.
It's a clever(?) way of checking if the month and day of the date of birth happened before or after the date from the event (litter) in order to properly calculate the number of years between the events (as the year part in itself isn't enough).
In this part:
( YEAR(date) - YEAR(birth) ) - ( RIGHT(date,5) < RIGHT(birth,5) )
the RIGHT(date,5) returns the month and day part like (03-30) and does a boolean less than comparison which returns either 0 or 1 depending on the result. This is then subtracted from the YEAR(date) - YEAR(birth) calculation so that the years between the events get adjusted correctly.