How to SELECT only the most recent of each group using SQL? - mysql

I have the following table:
TABLE sales
| id | name | date | amount |
|----|------|------------|--------|
| 1 | Mike | 2016-12-05 | 67.15 |
| 2 | Mike | 2016-12-09 | 98.24 |
| 3 | John | 2016-12-12 | 12.98 |
| 4 | Mike | 2016-12-19 | 78.48 |
| 5 | Will | 2016-12-19 | 175.26 |
| 6 | John | 2016-12-22 | 14.26 |
| 7 | John | 2016-12-23 | 13.48 |
I am trying to create a view that will group by the name column and return only the most resent amount. It should look like this:
TABLE sales_view
| id | name | date | amount |
|----|------|------------|--------|
| 4 | Mike | 2016-12-19 | 78.48 |
| 5 | Will | 2016-12-19 | 175.26 |
| 7 | John | 2016-12-23 | 13.48 |
I'm not sure how to go about making this. I would imagine I would need sub-queries, but I know that SQL get mad if you try to use them inside of views.

You can use a tuple and a subquery with group by for max(date)
select * from sales
where (name, date) in ( select name, max(date)
from sales
group by name)

Related

select and group by same value mysql

i have table with data like this below
| id | wallet_id | wallet_name | deposit | |
|----|-----------|-------------|---------|---|
| 1 | 12 | a_wallet | 10 | |
| 2 | 14 | c_wallet | 12 | |
| 3 | 12 | a_wallet | 24 | |
| 4 | 15 | e_wallet | 50 | |
| 5 | 14 | c_wallet | 10 | |
| 6 | 15 | e_wallet | 22 | |
i want to select and group with same wallet_id, probably something like this
| wallet_id | id | wallet_name |
|-----------|----|-------------|
| 12 | 1 | a_wallet |
| | 3 | a_wallet |
| 14 | 2 | c_wallet |
| | 5 | c_wallet |
| 15 | 4 | e_wallet |
| | 6 | e_wallet |
i already try
select wallet_id, id, wallet_name from wallet group by wallet_id
but it shows like usual select query with no grouping.
Kindly need your help, thanks
We would generally handle your requirement from the presentation layer (e.g. PHP), but if you happen to be using MySQL 8+, here is a way to do this directly from MySQL:
SELECT
CASE WHEN ROW_NUMBER() OVER (PARTITION BY wallet_id ORDER BY id) = 1
THEN wallet_id END AS wallet_id,
id,
wallet_name
FROM wallet w
ORDER BY w.wallet_id, id;

Multiple aggregations and group by in single query

I have an SQL table with roughly the following structure:
Employee| date | department | Country | Designation
What I would like is to get results with the following structure:
count_emp_per_department | count_emp_per_country | count_emp_per_designation |
Currently I am using UNION ALL, that is constructing a query similar to that one:
SELECT emp_ID, NULL, count(1)
FROM employee
GROUP BY country
UNION ALL
SELECT NULL, emp_ID, count(1)
FROM film
GROUP BY designation
Is this the most effective way to perform multiple aggregations and return all of them in a single result set in Hive?
Kindly share if you new approach which can optimize/enhance performance.
Not sure whether its a real requirement.. as the output isnt that useful.. anyway
Here is the structure and query.
+-----------+------------+----------+
| col_name | data_type | comment |
+-----------+------------+----------+
| emp | int | |
| dt | date | |
| dept | string | |
| country | string | |
| desig | string | |
+-----------+------------+----------+
+--------+-------------+---------+------------+----------+
| t.emp | t.dt | t.dept | t.country | t.desig |
+--------+-------------+---------+------------+----------+
| 1 | 2020-02-02 | human | usa | hr |
| 2 | 2020-02-02 | dir | usa | hr |
| 3 | 2020-02-02 | dir | canada | it |
+--------+-------------+---------+------------+----------+
with q1 as (select dept,count(*) as deptcount from t group by dept),
q2 as (select country,count(*) as countrycount from t group by country),
q3 as (select desig,count(*) as desigcount from t group by desig)
select * from q1, q2, q3;
output will be like this..
+----------+---------------+-------------+------------------+-----------+----------------+
| q1.dept | q1.deptcount | q2.country | q2.countrycount | q3.desig | q3.desigcount |
+----------+---------------+-------------+------------------+-----------+----------------+
| dir | 2 | canada | 1 | hr | 2 |
| dir | 2 | usa | 2 | hr | 2 |
| dir | 2 | canada | 1 | it | 1 |
| dir | 2 | usa | 2 | it | 1 |
| human | 1 | canada | 1 | hr | 2 |
| human | 1 | usa | 2 | hr | 2 |
| human | 1 | canada | 1 | it | 1 |
| human | 1 | usa | 2 | it | 1 |
+----------+---------------+-------------+------------------+-----------+----------------+

Inequality in Mysql with count()

I have the following structure :
Table Author :
idAuthor,
Name
+----------+-------+
| idAuthor | Name |
+----------+-------+
| 1 | Renee |
| 2 | John |
| 3 | Bob |
| 4 | Bryan |
+----------+-------+
Table Publication:
idPublication,
Title,
Type,
Date,
Journal,
Conference
+---------------+--------------+------+-------------+------------+-----------+
| idPublication | Title | Date | Type | Conference | Journal |
+---------------+--------------+------+-------------+------------+-----------+
| 1 | Flower thing | 2008 | book | NULL | NULL |
| 2 | Bees | 2009 | article | NULL | Le Monde |
| 3 | Wasps | 2010 | inproceding | KDD | NULL |
| 4 | Whales | 2010 | inproceding | DPC | NULL |
| 5 | Lyon | 2011 | article | NULL | Le Figaro |
| 6 | Plants | 2012 | book | NULL | NULL |
| 7 | Walls | 2009 | proceeding | KDD | NULL |
| 8 | Juices | 2010 | proceeding | KDD | NULL |
| 9 | Fruits | 2010 | proceeding | DPC | NULL |
| 10 | Computers | 2010 | inproceding | DPC | NULL |
| 11 | Phones | 2010 | inproceding | DPC | NULL |
| 12 | Creams | 2010 | proceeding | DPC | NULL |
| 13 | Love | 2010 | proceeding | DPC | NULL |
+---------------+--------------+------+-------------+------------+-----------+
Table author_has_publication :
Author_idAuthor,
Publication_idPublication
+-----------------+---------------------------+
| Author_idAuthor | Publication_idPublication |
+-----------------+---------------------------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 1 | 5 |
| 2 | 5 |
| 3 | 5 |
| 3 | 6 |
| 4 | 7 |
| 4 | 8 |
| 4 | 9 |
| 4 | 10 |
| 3 | 11 |
| 3 | 12 |
| 2 | 13 |
+-----------------+---------------------------+
I want to obtain the list of all authors having published at least 2 times at conference DPC in 2010.
I achieved to get the list of autors that have published something, and the number of publication for each, but I can't get my 'at least 2' factor.
My following query
SELECT author.name, COUNT(name) FROM author INNER JOIN author_has_publication ON author.idAuthor=author_has_publication.Author_idAuthor INNER JOIN publication ON author_has_publication.Publication_idPublication=publication.idPublication AND publication.date=2010 AND publication.conference='DPC'GROUP BY author.name;
returns the following result (which is good)
+-------+-------------+
| name | COUNT(name) |
+-------+-------------+
| Bob | 2 |
| Bryan | 3 |
| John | 1 |
+-------+-------------+
but when I try to select only the one with a count(name)>=2, i got an error.
I tried this query :
SELECT author.name, COUNT(name) FROM author INNER JOIN author_has_publication ON author.idAuthor=author_has_publication.Author_idAuthor INNER JOIN publication ON author_has_publication.Publication_idPublication=publication.idPublication AND publication.date=2010 AND publication.conference='DPC'GROUP BY author.name WHERE COUNT(name)>=2;
When you use aggregation funcion you can filter with a proper operator named HAVING
Having worok on the result of the query (then pn the aggrgated result like count() ) instead of where that work on the original value of the tables rows
SELECT author.name, COUNT(name)
FROM author INNER JOIN author_has_publication
ON author.idAuthor=author_has_publication.Author_idAuthor
INNER JOIN publication
ON author_has_publication.Publication_idPublication=publication.idPublication
AND publication.date=2010 AND publication.conference='DPC'
GROUP BY author.name
HAVING COUNT(name)>=2;

How can I count the users with more than 1 Order?

I'm working on a MySQL database and I need to query the database and find out the users with more than one order. I tried using COUNT() but I cannot get it right. Can you please explain the correct way to do this?.
Here are my tables:
User
+-------------+----------+------------------+------------+
| userID | fName | email | phone |
+-------------+----------+------------------+------------+
| adele012 | Adele | aash#gmail.com | 0123948498 |
| ana022 | Anna | ashow#gmail.com | 0228374847 |
| david2012 | David | north#gmail.com | 902849302 |
| jefAlan | Jeffery | jefal#gmail.com | 0338473837 |
| josquein | Joseph | jquein#gmail,com | 0098374678 |
| jweiz | John | jwei#gmail.com | 3294783784 |
| jwick123 | John | jwik#gmail.com | 0998398390 |
| kenwipp | Kenneth | kwip#gmail.com | 0112938394 |
| mathCler | Maththew | matc#gmail.com | 0238927483 |
| natalij2012 | Natalie | nj#gmail.com | 1129093210 |
+-------------+----------+------------------+------------+
Orders
+---------+------------+-------------+-------------+
| orderID | date | User_userID | orderStatus |
+---------+------------+-------------+-------------+
| 1 | 2012-01-10 | david2012 | Delivered |
| 2 | 2012-01-15 | jweiz | Delivered |
| 3 | 2013-08-15 | david2012 | Delivered |
| 4 | 2013-03-15 | natalij2012 | Delivered |
| 5 | 2014-03-04 | josquein | Delivered |
| 6 | 2014-01-15 | jweiz | Delivered |
| 7 | 2014-02-15 | josquein | Delivered |
| 8 | 2015-10-12 | jwick123 | Delivered |
| 9 | 2015-02-20 | ana022 | Delivered |
| 10 | 2015-11-20 | kenwipp | Processed |
+---------+------------+-------------+-------------+
select user_userID, count(*) as orders_count from orders
group by user_userID having orders_count > 1
if you want additional data from your users table, you can do:
select * from user where user_id in (
select user_userID as orders_count from orders
group by user_userID having orders_count > 1
)

Complex MySQL query summing joined records where parent and child ids are equal

Maybe this will be an easy one for some of you MySQL masters who see this stuff like a level 3 children's book.
I have multiple tables that I'm joining to produce statistical data for a report and I'm getting tripped up at the moment trying to figure it out. It's obviously imperative the figures are correct because it impacts a number of decisions going forward.
Here's the lay of the land (not the full picture, but you'll get the point):
Affiliate Table
+----+-----------+------------+---------------------+
| id | firstname | lastname | created_date |
+----+-----------+------------+---------------------+
| 1 | Mike | Johnson | 2010-11-22 17:44:37 |
| 2 | Trevor | Wilson | 2010-12-23 16:24:24 |
| 3 | Bob | Parker | 2011-11-04 10:33:49 |
+----+-----------+------------+---------------------+
Now our query should only find results for Bob Parker (id 3) so I'll only show example results for Bob.
Affiliate Link Table
+-----+-----------+--------------+-----------+----------+---------------------+
| id | parent_id | affiliate_id | link_type | linkhash | created_date |
+-----+-----------+--------------+-----------+----------+---------------------+
| 21 | NULL | 3 | PRODUCT | fa2e82a7 | 2011-06-15 16:18:37 |
| 27 | NULL | 3 | PRODUCT | 55de2ae7 | 2011-06-23 01:03:00 |
| 28 | NULL | 3 | PRODUCT | 02cae72f | 2011-06-23 01:03:00 |
| 29 | 27 | 3 | PRODUCT | a4dfb2c8 | 2011-06-23 01:03:00 |
| 30 | 28 | 3 | PRODUCT | 72cea1b2 | 2011-06-23 01:03:00 |
| 36 | 21 | 3 | PRODUCT | fa2e82a7 | 2011-06-23 01:07:03 |
| 59 | 21 | 3 | PRODUCT | ec33413f | 2011-11-04 17:49:17 |
| 60 | 27 | 3 | PRODUCT | f701188c | 2011-11-04 17:49:17 |
| 69 | 21 | 3 | PRODUCT | 6dfb89fd | 2011-11-04 17:49:17 |
+-----+-----------+--------------+-----------+----------+---------------------+
Affiliate Stats
+--------+--------------+--------------------+----------+---------------------+
| id | affiliate_id | link_id | order_id | type | created_date |
+--------+--------------+---------+----------+----------+---------------------+
| 86570 | 3 | 21 | NULL | CLICK | 2013-01-01 00:07:31 |
| 86574 | 3 | 21 | NULL | PAGEVIEW | 2013-01-01 00:08:53 |
| 86579 | 3 | 21 | 411 | SALE | 2013-01-01 00:09:52 |
| 86580 | 3 | 36 | NULL | CLICK | 2013-01-01 00:09:55 |
| 86582 | 3 | 36 | NULL | PAGEVIEW | 2013-01-01 00:09:56 |
| 86583 | 3 | 28 | NULL | CLICK | 2013-01-01 00:11:04 |
| 86584 | 3 | 28 | NULL | PAGEVIEW | 2013-01-01 00:11:04 |
| 86586 | 3 | 30 | NULL | CLICK | 2013-01-01 00:30:18 |
| 86587 | 3 | 30 | NULL | PAGEVIEW | 2013-01-01 00:30:20 |
| 86611 | 3 | 69 | NULL | CLICK | 2013-01-01 00:40:19 |
| 86613 | 3 | 69 | NULL | PAGEVIEW | 2013-01-01 00:40:19 |
| 86619 | 3 | 69 | 413 | SALE | 2013-01-01 00:42:12 |
| 86622 | 3 | 60 | NULL | CLICK | 2013-01-01 00:46:00 |
| 86624 | 3 | 60 | NULL | PAGEVIEW | 2013-01-01 00:46:01 |
| 86641 | 3 | 60 | NULL | PAGEVIEW | 2013-01-01 00:55:58 |
| 86642 | 3 | 30 | 415 | SALE | 2013-01-01 00:56:35 |
| 86643 | 3 | 28 | NULL | PAGEVIEW | 2013-01-01 00:56:43 |
| 86644 | 3 | 60 | 417 | SALE | 2013-01-01 00:56:52 |
+--------+--------------+---------+----------+----------+---------------------+
Orders
+------+--------------+---------+---------------------+
| id | affiliate_id | total | created_date |
+------+--------------+---------+---------------------+
| 411 | 3 | 138.62 | 2013-01-01 00:09:50 |
| 413 | 3 | 312.87 | 2013-01-01 00:09:52 |
| 415 | 3 | 242.59 | 2013-01-01 00:09:55 |
| 417 | 3 | 171.18 | 2013-01-01 00:09:55 |
+------+--------------+---------+---------------------+
Now the results that I need should look like this (only show main/parent link id)
+---------+---------+
| link_id | total |
+---------+---------+
| 21 | 451.49 | <- 1 order from parent (21), 1 from child (69)
| 27 | 171.18 | <- 1 order from child (69)
| 28 | 242.59 | <- 1 order from child (30)
+---------+---------+
I'm not quite sure how to write the query so that I can sum where affiliate_link.id and affiliate_link.parent_id are combined. Is this even possible with a couple of JOINs and GROUPing?
I'm not too sure why you have denormalised affiliate_id (by placing it in each table) and, therefore, whether one can rely on all Stats and Orders that stem from a particular Link to have the same affiliate_id as that Link.
If it's possible, I'd suggest changing the AffiliateLink.parent_id column such that parent records point to themselves (rather than NULL):
UPDATE AffiliateLink SET parent_id = id WHERE parent_id IS NULL
Then it's a simple case of joining and grouping:
SELECT AffiliateLink.parent_id AS link_id,
SUM(Orders.total) AS total
FROM AffiliateLink
JOIN AffiliateStats ON AffiliateStats.link_id = AffiliateLink.id
JOIN Orders ON Orders.id = AffiliateStats.order_id
WHERE AffiliateLink.affiliate_id = 3
GROUP BY AffiliateLink.parent_id
See it on sqlfiddle.
If it's not possible to make the change, you can effectively create the resulting AffiliateLink table using UNION (but beware the performance implications, as MySQL will not be able to use indexes on the result):
(
SELECT parent_id, id, affiliate_id FROM AffiliateLink WHERE parent_id IS NOT NULL
UNION ALL
SELECT id , id, affiliate_id FROM AffiliateLink WHERE parent_id IS NULL
) AS AffiliateLink
See it on sqlfiddle.