Find the Maximum number in mysql - mysql

How do I find the most popular book among all customers from the table above? (cid = 'customer id')?
I have
select Title, sum(c.quantity) from cart c group by c.ISBN;
which gives me the following results
+-----------------------------------------+-----------------+
| Title | sum(c.quantity) |
+-----------------------------------------+-----------------+
| Writing Skills | 5 |
| Fundamentals of Database Systems | 2 |
| Database Management Systems | 5 |
| Data Mining, Practical Machine Learning | 4 |
+-----------------------------------------+-----------------+
I know the Max() function in mysql can achieve my goal, but I do not know to implement Max() and Sum() together.
Thanks!

To get most popular book/books you can use following query
select c.ISBN,c.Title, sum(c.quantity) soldQuantity
from cart c
group by c.ISBN,c.Title
having soldQuantity = (
select sum(quantity)
from cart
group by ISBN,Title
order by sum(quantity) desc
limit 1
)
Note there can be more than 1 books which share same highest quantity

The following SQL statement should give you the book with the most quantity
SELECT
Title,
sum(c.quantity) AS total_count
FROM
cart c
GROUP BY
c.ISBN
ORDER BY
total_count DESC
LIMIT 1
Note: You really should put the books in a seperate table titled "books" with two columns, "id" and "title". You can then change the "title" column in your original table to "book_id" and make it a foreign key to books.id. This will greatly improve the speed of your SQL calls.
Hope this helps!

Hi one approach would be using sub queries like this:
SELECT TITLE, MAX (SUMMATION)
FROM (SELECT TITLE, SUM (C.QUANTITY) SUMMATION
FROM CART C
GROUP BY TITLE, C.ISBN) LIST
GROUP BY TITLE, SUMMATION

Related

MySQL COUNT(DISTINCT) giving wrong values with GROUP BY

I have a table that contains custom user analytics data. I was able to pull the number of unique users with a query:
SELECT COUNT(DISTINCT(user_id)) AS 'unique_users'
FROM `events`
WHERE client_id = 123
And this will return 16728
This table also has a column of type DATETIME that I would like to group the counts by. However, if I add a GROUP BY to the end of it, everything groups properly it seems except the totals don't match. My new query is this:
SELECT COUNT(DISTINCT(user_id)) AS 'unique_users', DATE(server_stamp) AS 'date'
FROM `events`
WHERE client_id = 123
GROUP BY DATE(server_stamp)
Now I get the following values:
|-----------------------------|
| unique_users | date |
|---------------|-------------|
| 2650 | 2019-08-26 |
| 3486 | 2019-08-27 |
| 3475 | 2019-08-28 |
| 3631 | 2019-08-29 |
| 3492 | 2019-08-30 |
|-----------------------------|
Totaling to 16734. I tried using a sub query to get the distinct users then count and group in the main query but no luck there. Any help in this would be greatly appreciated. Let me know if there is further information to help diagnosis.
A user, who is connected with events on multiple days (e.g. session starts before midnight and ends afterwards), will occur the number of these days times in the new query. This is due to the fact, that the first query performs the DISTINCT over all rows at once while the second just removes duplicates inside each groups. Identical values in different groups will stay untouched.
So if you have a combination of DISTINCT in the select clause and a GROUP BY, the GROUP BY will be executed before the DISTINCT. Thus without any restrictions you cannot assume, that the COUNT(DISTINCT user_id) of the first query and the sum over the COUNT(DISTINCT user_id) of all groups is the same.
Xandor is absolutely correct. If a user logged on 2 different days, There is no way your 2nd query can remove them. If you need data grouped by date, You can try below query -
SELECT COUNT(user_id) AS 'unique_users', DATE(MIN_DATE) AS 'date'
FROM (SELECT user_id, MIN(DATE(server_stamp)) MIN_DATE -- Might be MAX
FROM `events`'
WHERE client_id = 123
GROUP BY user_id) X
GROUP BY DATE(server_stamp);

MySQL query, two tables with order group by

I have two tables, bills and linesbill. I need all the products that a customer has ever bought. I've gotten this to work:
SELECT referencia, codcliente, pvpunitario, t2.fecha FROM
lineasfacturascli T1
INNER JOIN facturascli T2 ON T1.idfactura = T2.idfactura
WHERE T2.codcliente = "000001"
GROUP BY referencia
But I need get the last price that the customer has paid for each product. I'm trying to order by "fecha"->(date) but it does not work.
Tables structure
facturascli
idfactura(id bill),
codcliente(client id),
fecha(date)
lineasfacturascli
referencia(name of product),
idfactura(id bill)
pvpunitario(price)
Edit
DRapp solution works but I also need to handle the case that a customer buys it in the same day get only the lower price:
With the solution provided the result is:
|Referencia| |MostRecentDatePerItem| |MostRecentPricePerItem|
| pendrive | | 2017-03-02 | | 50 |
| pendrive | | 2017-03-02 | | 10 |
| samsung | | 2017-03-02 | | 50 |
| linux car| | 2017-04-26 | | 9.99 |
I need:
|Referencia| |MostRecentDatePerItem| |MostRecentPricePerItem|
| pendrive | | 2017-03-02 | | 10 |
| samsung | | 2017-03-02 | | 50 |
| linux car| | 2017-04-26 | | 9.99 |
Thanks
I would start with an inner pre-query of all line items for a specific person with a max date per item as a group by. So if a person ordered the 10 things multiple times over say... 50 orders, you would still have the final list of 10 things, but also the most recent date the thing was ordered.
The following is based on not exactly knowing your structures, nor sample data (please provide for future). Also, you should always qualify your table columns in a query with the corresponding table alias reference so users know which field comes from what table. I have to assume the "pvpunitario" column is from the line item details as the price, but basic translation appears to be "unit" not price. You will have to adjust accordingly if I am inaccurate on my impression.
select
T1.referencia,
max( t2.fecha ) as MostRecentDatePerItem
FROM
lineasfacturascli T1
INNER JOIN facturascli T2
ON T1.idfactura = T2.idfactura
WHERE
T2.codcliente = "000001"
GROUP BY
T1.referencia
So this will give us just the products and the maximum date ever ordered by a single client. Now, we take this result as a basis to the original query, re-joined to the line items / order headers that specifically match the corresponding MostRecentDatePerItem.
select
TT1.Referencia,
PQ.MostRecentDatePerItem,
TT1.pvpunitario as MostRecentPricePerItem
from
lineasfacturascli TT1
JOIN
(select
T1.referencia,
max( t2.fecha ) as MostRecentDatePerItem
FROM
lineasfacturascli T1
INNER JOIN facturascli T2
ON T1.idfactura = T2.idfactura
WHERE
T2.codcliente = "000001"
GROUP BY
T1.referencia ) PQ
on TT1.Referencia = PQ.Referencia
JOIN facturascli TT2
ON TT1.idfactura = TT2.idfactura
AND PQ.MostRecentDatePerItem = TT2.Fecha
where
TT2.codcliente = "000001"
To clarify what is going on. The inner query (now alias "PQ" -- PreQuery), is just those qualifying items for the one client in question with the most recent date said item was purchased.
So now back to the original list of all order line items joined to this table keeps the reference product ID linked. Now, we go again to the order header table and still apply the same client code, but ALSO joined on the same FETCHA date as the maximum date found for the transaction. So only THEN do we want to grab the detail level price / unit information for said product.
Hopefully this helps direct your final solution. If I am incorrect on any pieces, you should EDIT your original question and supply the additional missing details / alias references / sample data. Then you can reply comment for follow-up support.
Answer per Comment.
To get the minimum price, you would just adjust the outer select and add a group by. Since the item is the same, the group by will only group for the prices on that specific day. Change the above to...
select
TT1.Referencia,
PQ.MostRecentDatePerItem,
MIN( TT1.pvpunitario ) as LeastPricePerItemOnThisDate
(same rest of query)
GROUP BY
TT1.Referencia,
PQ.MostRecentDatePerItem

SQL, Find orders where strict critera is met, Match item, not if other items purchased

I have stumped all the IT people at my work with this one, so wondeirng if anyone can help.
I need to extract from an order table anyone who has only purchased a specific product type, (if they have order the product type and any other product types i dont want to know who you are)
for example the table is roughly
---------------------------------------------------------------------------------------
Order ID | item code | Name |
----------------------------------------------------------------------------------------
1 | ADA | item 1
2 | ADA | item 1
2 | GGG | item 2
3 | ADA | item 1
----------------------------------------------------------------------------------------
So i want to find all the order IDs of people who only purchased item code ADA, BUT not if they purchased over items, so the output of this query should be order ID 1 & 3 and skipping order 2 as this had a different item.
Would really appriciate it if anyone could help.
Assuming an order can't have multiple records with the same ItemCode, you could use:
SELECT *
FROM Orders
WHERE OrderID IN (
SELECT OrderID
FROM Orders
GROUP BY OrderID HAVING COUNT(*) = 1
)
AND ItemCode = 'ADA'
If an order could have multiple records with the same ItemCode then you'd have to change the SELECT * to SELECT DISTINCT * and then COUNT(*) to COUNT(DISTINCT ItemCode)
Based on your current explanation and example, the below should work. However, there are outstanding questions in the comments which may change the actual correct solution.
SELECT
O.OrderId, MAX(itemCode), MAX(Name)
FROM
Orders O
INNER JOIN
(SELECT
OrderId
FROM
Orders
WHERE
itemCode = 'ADA') ADA
ON
O.OrderId = ADA.OrderId
GROUP BY
O.OrderId
HAVING
COUNT(*) = 1

select min value of a field from joins table

CREATE VIEW products_view
AS
Hi guys ! I've tree tables:
Products
Categories
Prices
A product belongs to one category and may has more prices.
consider this set of data:
Product :
id title featured category_id
1 | bread | yes | 99
2 | milk | yes | 99
3 | honey | yes | 99
Price :
id product_id price quantity
1 | 1 | 99.99 | 10
2 | 1 | 150.00 | 50
3 | 2 | 33.10 | 20
4 | 2 | 10.00 | 11
I need to create a view, a full list of products that for each product select the min price and its own category.
eg.
id title featured cat.name price quantity
1 | bread | yes | food | 99.99 | 10
I tried the following query but in this way I select only the min Price.price value but Price.quantity, for example, came from another row. I should find the min Price.price value and so use the Price.quantity of this row as correct data.
CREATE VIEW products_view
AS
SELECT `Prod`.`id`, `Prod`.`title`, `Prod`.`featured`, `Cat`.`name`, MIN(`Price`.`price`) as price,`Price`.`quantity`
FROM `products` AS `Prod`
LEFT JOIN `prices` AS `Price` ON (`Price`.`product_id` = `Prod`.`id`)
LEFT JOIN `categories` AS `Cat` ON (`Prod`.`category_id` = `Cat`.`id`)
GROUP BY `Prod`.`id`
ORDER BY `Prod`.`id` ASC
My result is:
id title featured cat.name price quantity
1 | bread | yes | food | 99.99 | **50** <-- wrong
Can you help me ? Thx in advance !
As documented under MySQL Extensions to GROUP BY (emphasis added):
In standard SQL, a query that includes a GROUP BY clause cannot refer to nonaggregated columns in the select list that are not named in the GROUP BY clause. For example, this query is illegal in standard SQL because the name column in the select list does not appear in the GROUP BY:
SELECT o.custid, c.name, MAX(o.payment)
FROM orders AS o, customers AS c
WHERE o.custid = c.custid
GROUP BY o.custid;
For the query to be legal, the name column must be omitted from the select list or named in the GROUP BY clause.
MySQL extends the use of GROUP BY so that the select list can refer to nonaggregated columns not named in the GROUP BY clause. This means that the preceding query is legal in MySQL. You can use this feature to get better performance by avoiding unnecessary column sorting and grouping. However, this is useful primarily when all values in each nonaggregated column not named in the GROUP BY are the same for each group. The server is free to choose any value from each group, so unless they are the same, the values chosen are indeterminate. Furthermore, the selection of values from each group cannot be influenced by adding an ORDER BY clause. Sorting of the result set occurs after values have been chosen, and ORDER BY does not affect which values within each group the server chooses.
What you are looking for is the group-wise minimum, which can be obtained by joining the grouped results back to the table:
SELECT Prod.id, Prod.title, Prod.featured, Cat.name, Price.price, Price.quantity
FROM products AS Prod
LEFT JOIN categories AS Cat ON Prod.category_id = Cat.id
LEFT JOIN (
prices AS Price NATURAL JOIN (
SELECT product_id, MIN(price) AS price
FROM prices
GROUP BY product_id
) t
) ON Price.product_id = Prod.id
ORDER BY Prod.id

MySQL: Transfer Data Based on a Column Without Also Transferring That Column

My table stores revision data for my CMS entries. Each entry has an ID and a revision date, and there are multiple revisions:
Table: old_revisions
+----------+---------------+-----------------------------------------+
| entry_id | revision_date | entry_data |
+----------+---------------+-----------------------------------------+
| 1 | 1302150011 | I like pie. |
| 1 | 1302148411 | I like pie and cookies. |
| 1 | 1302149885 | I like pie and cookies and cake. |
| 2 | 1288917372 | Kittens are cute. |
| 2 | 1288918782 | Kittens are cute but puppies are cuter. |
| 3 | 1288056095 | Han shot first. |
+----------+---------------+-----------------------------------------+
I want to transfer some of this data to another table:
Table: new_revisions
+--------------+----------------+
| new_entry_id | new_entry_data |
+--------------+----------------+
| | |
+--------------+----------------+
I want to transfer entry_id and entry_data to new_entry_id and new_entry_data. But I only want to transfer the most recent version of each entry.
I got as far as this query:
INSERT INTO new_revisions (
new_entry_id,
new_entry_data
)
SELECT
entry_id,
entry_data,
MAX(revision_date)
FROM old_revisions
GROUP BY entry_id
But I think the problem is that I'm trying to insert 3 columns of data into 2 columns.
How do I transfer the data based on the revision date without transferring the revision date as well?
You can use the following query:
insert into new_revisions (new_entry_id, new_entry_data)
select o1.entry_id, o1.entry_data
from old_revisions o1
inner join
(
select max(revision_date) maxDate, entry_id
from old_revisions
group by entry_id
) o2
on o1.entry_id = o2.entry_id
and o1.revision_date = o2.maxDate
See SQL Fiddle with Demo. This query gets the max(revision_date) for each entry_id and then joins back to your table on both the entry_id and the max date to get the rows to be inserted.
Please note that the subquery is only returning the entry_id and date, this is because we want to apply the GROUP BY to the items in the select list that are not in an aggregate function. MySQL uses an extension to the GROUP BY clause that allows columns in the select list to be excluded in a group by and aggregate but this could causes unexpected results. By only including the columns needed by the aggregate and the group by will ensure that the result is the value you want. (see MySQL Extensions to GROUP BY)
From the MySQL Docs:
MySQL extends the use of GROUP BY so that the select list can refer to nonaggregated columns not named in the GROUP BY clause. ... You can use this feature to get better performance by avoiding unnecessary column sorting and grouping. However, this is useful primarily when all values in each nonaggregated column not named in the GROUP BY are the same for each group. The server is free to choose any value from each group, so unless they are the same, the values chosen are indeterminate. Furthermore, the selection of values from each group cannot be influenced by adding an ORDER BY clause. Sorting of the result set occurs after values have been chosen, and ORDER BY does not affect which values the server chooses.
If you want to enter the last entry you need to filter it before:
select entry_id, max(revision_date) as maxDate
from old_revisions
group by entry_id;
Then use this as a subquery to filter the data you need:
insert into new_revisions (new_entry_id, new_entry_data)
select entry_id, entry_data
from old_revisions as o
inner join (
select entry_id, max(revision_date) as maxDate
from old_revisions
group by entry_id
) as a on o.entry_id = a.entry_id and o.revision_date = a.maxDate