Can I compare different rows in the same MySQL table (SQL) - mysql

Is there a way to compare different rows in the same MySQL table? I want to count how many users have changed their names.
Here is roughly what I got in the MySQL log table...
id userid name
1 1 Joe
2 1 Joe
3 1 Joe
4 2 Fiona
5 3 Mark
6 3 Marcel
7 3 Marcel
8 4 Mary
9 4 Marie
You can see that Joe's name has not changed even though he is in the log table 3 times. "Mark" was changed to "Marcel" and "Mary" was changed to "Marie". So if this was the whole of the table, I want to know that 2 people have changed their names (out of four).
SELECT userid, GROUP_CONCAT(name) FROM tablename GROUP BY userid ORDER BY userid DESC
I can examine the output with a scripting language (PHP), I'm just wondering if there is something I can do in SQL that would be neater and only give me the names that are changed.
I'm not sure if this is possible. Haven't found a solution to this yet, if it's a duplicate please let me know. Thanks.

How about using a HAVING clause?
SELECT userid
FROM tablename
GROUP BY userid
HAVING MIN(name) <> MAX(name)
ORDER BY userid DESC;
If you want the names without duplicates:
SELECT userid, GROUP_CONCAT(DISTINCT name)
FROM tablename
GROUP BY userid
HAVING MIN(name) <> MAX(name)
ORDER BY userid DESC;

Related

How to read records that matches multiple values in the same field?

I am trying to read records that match multiple values in the same field.
Example table : A
UserID License
1 DOG
1 CAT
1 FISH
2 DOG
2 CAT
3 FISH
4 CAT
4 DOG
4 FISH
5 CAT
5 FISH
How can I pull the UserIDs that have all three Licenses DOG, CAT and FISH ?
I am not sure how I could use INNER JOIN here since there are no two tables.
What is the best approach here ?
Thank you
PG
Don't even think about unnecessary INNER JOIN for this simple task. Let's do it using IN
SELECT UserID FROM A WHERE License IN('DOG','CAT','FISH');
N.B But still I'm little bit confused with this line though How can I pull the UserIDs that have all three Licenses DOG, CAT and FISH ?
Edited: This eliminate my confusion about all, try like this way and grab only the UserId from the output.
SELECT UserID,count(*) as lnt FROM A WHERE
License IN('DOG','CAT','FISH')
group by UserId having lnt = 3;
Output:
UserID lnt
1 3
4 3
Fiddle: http://sqlfiddle.com/#!9/e563ef/4
You can use case when... in your sql, like this:
SELECT UserID, SUM(CASE WHEN License IN ("DOG", "CAT", "FISH") THEN 1 ELSE 0 END) AS LICENSE_COUNT
FROM EXAMPLE_TABLE
GROUP BY UserID
HAVING LICENSE_COUNT = 3
"How can I pull the UserIDs that have all three Licenses DOG, CAT and FISH ?"
Like this:
SELECT USERID, COUNT(*) AS LICENSE_COUNT
FROM EXAMPLE_TABLE
GROUP BY USERID
HAVING COUNT(*) = 3
dbfiddle here
try to like this:
select userid
from example_table
WHERE License IN('DOG','CAT','FISH') group by user_id having count(distinct License)=3
As other answers stated, it is better to use IN operator instead of Join. You can get the desired result even without using group by or HAVING. Try this
Select DISTINCT(UserId) from A
Where UserID IN(Select userId from A where License='DOG')
AND UserID IN (Select UserId from A where License='CAT')
AND UserID IN (Select UserId from A where License='FISH')

MySQL: Count occurrences of distinct values for each row

Based on an example already given, I would like to ask my further question.
MySQL: Count occurrences of distinct values
example db
id name
----- ------
1 Mark
2 Mike
3 Paul
4 Mike
5 Mike
6 John
7 Mark
expected result
name count
----- -----
Mark 2
Mike 3
Paul 1
Mike 3
Mike 3
John 1
Mark 2
In my opinion 'GROUP BY' doesn't help.
Thank you very much.
Simplest approach would be using Count() as Window Function over a partition of name; but they are available only in MySQL 8.0.2 and onwards.
However, another approach is possible using a Derived Table. In a sub-select query (Derived Table), we will identify the counts for each unique name. Now, we simply need to join this to the main table, to show counts against each name (while not doing a grouping on them):
SELECT
t1.name,
dt.total_count
FROM your_table AS t1
JOIN
(
SELECT name,
COUNT(*) AS total_count
FROM your_table
GROUP BY name
) AS dt ON dt.name = t1.name
ORDER BY t1.id
If MySQL 8.0.2+ is available, the solution would be less verbose:
SELECT
name,
COUNT(*) OVER (PARTITION BY name) AS total_count
FROM your_table

MySQL group multiple rows based on DISTINCT value

I need to display the last 2 results from a table (results), the results are comprised of several rows with matching submissionId, The number of rows per submission is unknown, and of course I prefer a single query.
Here is the DB table structure
submissionId input value
1 name jay
1 phone 123-4567
1 email test#gmail.com
2 name mo
2 age 32
3 name abe
3 email abe#gmail.com
4 name jack
4 phone 123-4567
4 email jack#gmail.com
Desierd results:
submissionId input value
3 name abe
3 email abe#gmail.com
4 name jack
4 phone 123-4567
4 email jack#gmail.com
Or even better, if I can combine the rows like this:
3 name abe 3 email abe#gmail.com
4 name jack 4 phone 123-4567 4 email jack#gmail.com
One option here is to use a subquery to identify the most recent and next to most recent submissionId:
SELECT submissionId, input, value
FROM yourTable
WHERE submissionId >= (SELECT MAX(submissionId) FROM yourTable) - 1
ORDER BY submissionId
Demo here:
SQLFiddle
Update:
If your submissionId column were really a date type, and you wanted the most recent two dates in your result set, then the following query will achieve that. Note that the subquery in the WHERE clause, while ugly, is not correlated to the outer query. This means that the MySQL optimizer should be able to figure out that it only needs to run it once.
SELECT submissionDate, input, value
FROM yourTable
WHERE submissionDate >=
(SELECT MAX(CASE WHEN submissionDate = (SELECT MAX(submissionDate) FROM yourTable)
THEN '1000-01-01'
ELSE submissionDate
END) FROM yourTable)
ORDER BY submissionDate
SQLFiddle
You can use limit in subqueries in the from clause, so a typical way to write this is:
SELECT submissionDate, input, value
FROM t join
(select distinct submissionDate
from t
order by submissionDate desc
limit 2
) sd
on t.submissionDate = sd.submissionDate;
This is how the query looks like now, so i can get the results with a LIMIT, RANGE, and id/timestamp (with help of Tim and Gordon):
SELECT *
FROM rmyTable t
JOIN
(SELECT DISTINCT sd.submissionId
FROM myTable sd
WHERE sd.questionId = yourId
ORDER BY sd.submissionId
LIMIT 2
) t2
ON t.submissionId = t2.submissionId
WHERE t.formId = yourId
AND dateTime BETWEEN 0000 AND 1111

Guidance required for sql query

I have a database with one table as shown below. Here I'm trying to write a query to display the names of medication manufactured by the company that manufactures the most number of medications.
By looking at the table we could say the medication names which belongs to the company id 1 and 2 - because those company manufactures the most medication according to this table, but I'm not sure how to write a query for selecting the same i said before.
ID | COMPANY_ID | MEDICATION_NAME
1 1 ASPIRIN
2 1 GLUCERNA
3 2 SIBUTRAMINE
4 1 IBUPROFEN
5 2 VENOFER
6 2 AVONEN
7 4 ACETAMINOPHEN
8 3 ACETAMINO
9 3 GLIPIZIDE
Please share your suggestions. Thanks!
Several ways to do this. Here's one which first uses a subquery to get the maximum count, then another subquery to get the companies with that count, and finally the outer query to return the results:
select *
from yourtable
where companyid in (
select companyid
from yourtable
group by companyid
having count(1) = (
select count(1) cnt
from yourtable
group by companyid
order by 1 desc
limit 1
)
)
SQL Fiddle Demo
This Query might work. I have not tested but the logic is correct
SELECT MEDICATION_NAME
FROM TABLE where
COMPANY_ID=(SELECT
MAX(counted)
FROM ( SELECT COUNT(*) AS counted FROM TABLE ) AS counts);

getting individual records from a group by

I have two tables, one is a table of names with a category tag and the other is a table of scores for each name
ID Name Category
1 Dave 1
2 John 1
3 Lisa 2
4 Jim 2
and the score table is
PersonID Score
1 50
2 100
3 75
4 50
4 75
I would then like a query that returned something like
Category TotalScore Names
1 150 Dave, John
2 200 Lisa, Jim
Is this possible to do with one query?
I can get the totals with a sum query and grouping by category but cannot see a way to get the names as I would like.
Many thanks
You need to use group_concat:
select Category, sum(Score) as TotalScore, group_concat(Name) as Names from categories
join scores on scores.category = categories.category
group by category
Or even better:
group_concat(DISTINCT Name ORDER BY Name ASC SEPARATOR ',') as names
Just add group_concat(Name) as names into your sum query.
Here is a solution working for Postgres (which doesn't have a group_concat() function):
select category, sum(score) as TotalScore, array(select id from perso where category=P.category order by id) as Names from perso P JOIN scores S ON S."PersonID" = P.id GROUP BY category;
(I know this was a MySQL question, but nonetheless someone might google it up but needs an answer for Postgres :) )