SELECT distinct with multiple columns MySQL - mysql

I want to select distinct records in my database but I can't get it to work at all. I have tried DISTINCT and GROUP BY but still no luck.
Example:
This is my code:
SELECT
t1.room_id as Room_ID,
t1.room_name as Room_Name,
t2.price_date as Price_for_date,
t3.amount as Price ,
COUNT(t3.unit_id) as c
FROM
table1 AS t1
LEFT JOIN table3 AS t3 ON t1.room_id = t3.room_id
LEFT JOIN table2 AS t2 ON t3.price_room_id = t2.price_room_id
WHERE
t2.price_date BETWEEN (20180130) AND (20180530)
GROUP BY
t2.price_date,
t1.room_id
ORDER BY
t1.room_id,
t2.price_date DESC
T1:
id | room_id | room_name
-----------------------
1 | room1 | rm1
2 | room2 | rm2
3 | room3 | rm3
4 | room4 | rm4
5 | room5 | rm5
T2:
id | price_room_id | price_date
-------------------------------
1 | 000001 | 2018-01-30
2 | 000002 | 2018-02-30
3 | 000003 | 2018-03-30
4 | 000004 | 2018-04-30
5 | 000005 | 2018-05-30
T3:
id | room_id | price_room_id | amount
-------------------------------------
1 | room1 | 00001 | 100000
2 | room1 | 00002 | 101000
3 | room2 | 00002 | 110000
4 | room3 | 00003 | 200000
5 | room3 | 00004 | 300000
6 | room4 | 00001 | 100000
7 | room5 | 00005 | 350000
What I wanted is to select the room_id, price_room_id, and amount with its latest records between the given dates. From the table above I should get the following:
room_id | price_room_id | amount
-------------------------------------
room1 | 00002 | 101000
room2 | 00002 | 110000
room3 | 00004 | 200000
room4 | 00001 | 100000
room5 | 00005 | 350000
But what I'm getting is like this:
room_id | price_room_id | amount
-------------------------------------
room1 | 00002 | 101000
room1 | 00001 | 100000
room2 | 00002 | 110000
room3 | 00004 | 200000
room3 | 00003 | 110000
room4 | 00001 | 100000
room5 | 00005 | 350000

Try removing the Group by and put DISTINCT in SELECT. SELECT DISTINCT... because group by will group every room_id but in your case you just want to get the latest price_date.
SELECT DISTINCT (t1.room_id as Room_ID),
t1.room_name as Room_Name,
t2.price_room_id as Price_room_id,
t2.price_date as Price_for_date,
t3.amount as Price ,
COUNT(t3.unit_id) as c
FROM
table1 AS t1
LEFT JOIN table3 AS t3 ON t1.room_id = t3.room_id
LEFT JOIN table2 AS t2 ON t3.price_room_id = t2.price_room_id
WHERE
t2.price_date = max(t2.price_date)
ORDER BY
t1.room_id;

Unfortunately I don't have the reputation to comment but what #Caius Jard is saying is that each room_id has multiple price_room_ids which is reflected in the output you actually received. But the result that you want only has one price associated with each room_id so which price_room_id do you want to return for each room_id? From your comment, it seems like you want only the most recent price for each room? However, the initial query that you gave us also has some outputs that are not reflected with the example/desired output you gave. For example, COUNT(t3.unit_id) as c what do you want this output to be?
If you just want to show the latest price_date and COUNT(t3.unit_id) as c with only those latest prices you should probably filter by the latest price_date:
SELECT
t1.room_id as Room_ID,
t1.room_name as Room_Name,
t2.price_room_id as Price_room_id,
t2.price_date as Price_for_date,
t3.amount as Price ,
COUNT(t3.unit_id) as c
FROM
table1 AS t1
LEFT JOIN table3 AS t3 ON t1.room_id = t3.room_id
LEFT JOIN table2 AS t2 ON t3.price_room_id = t2.price_room_id
WHERE
t2.price_date = max(t2.price_date)
GROUP BY
t1.room_id
ORDER BY
t1.room_id;
EDIT:
Okay I think I understand now. I am not really sure how to get the max date from a date interval and I think this probably a super slow query but try this out:
SELECT
t1.room_id as Room_ID,
t1.room_name as Room_Name,
t2.price_room_id as Price_room_id,
t2.price_date as Price_for_date,
t3.amount as Price ,
COUNT(t3.unit_id) as c
FROM
table1 AS t1
LEFT JOIN table3 AS t3 ON t1.room_id = t3.room_id
LEFT JOIN table2 AS t2 ON t3.price_room_id = t2.price_room_id
WHERE
t2.price_date = (select max(t2.price_date) where t2.price_date BETWEEN '2018-01-30' AND '2018-05-30')
GROUP BY
t1.room_id
ORDER BY
t1.room_id;

Related

Is there better way to get the difference between two table with same fields?

I have two tables as below:
table1:
+----+----------+-------+
| id | order_id | price |
+----+----------+-------+
| 1 | 1024 | 20 |
| 2 | 1025 | 30 |
| 3 | 1026 | 35 |
| 4 | 1027 | 45 |
+----+----------+-------+
table2
+----+----------+-------+------+
| id | order_id | price | name |
+----+----------+-------+------+
| 1 | 1024 | 20 | a |
| 2 | 1025 | 30 | b |
| 3 | 1026 | 35 | c |
| 4 | 1027 | 40 | d |
+----+----------+-------+------+
What I want to do is just camparing fields order_id and price, and get the different content when order_id = 1027
Here is my humble opinion:
SELECT * FROM (
SELECT order_id, price FROM table1
UNION ALL
SELECT order_id, price FROM table2
) t
GROUP BY order_id, price
HAVING COUNT(*) = 1
# result
+----------+-------+
| order_id | price |
+----------+-------+
| 1027 | 40 |
| 1027 | 45 |
+----------+-------+
Is there any better way to get it.
Any commentary is very welcome. great thanks.
Another alternative would be to use a JOIN to find non-matching prices:
SELECT t1.order_id, t1.price AS table1_price, t2.price AS table2_price
FROM table1 t1
JOIN table2 t2 ON t2.order_id = t1.order_id AND t2.price != t1.price
Output:
order_id table1_price table2_price
1027 45 40
Demo on dbfiddle
If you also want to capture rows which exist in one table but not the other, then you will need a FULL OUTER JOIN, which MySQL doesn't support, and must be emulated using a UNION of a LEFT JOIN and a RIGHT JOIN:
SELECT *
FROM (SELECT t1.order_id AS order_id, t1.price AS table1_price, t2.price AS table2_price
FROM table1 t1
LEFT JOIN table2 t2 ON t2.order_id = t1.order_id
UNION
SELECT t2.order_id, t1.price AS table1_price, t2.price AS table2_price
FROM table1 t1
RIGHT JOIN table2 t2 ON t2.order_id = t1.order_id) t
WHERE table1_price != table2_price OR
table1_price IS NULL OR
table2_price IS NULL
Output:
order_id table1_price table2_price
1027 45 40
1028 50 null
1029 null 45
Demo on dbfiddle
You can use left join to get the values
SELECT table1.order_id, table1.price
FROM table1
LEFT JOIN table2 ON table2.order_id = table1.order_id AND table2.price != table1.price

MySQL queries, max & current rank for players

In the lists of players I need to find find the maximum rating and current rating
Petr | 1 | 2016-12-01 00:00:00
Petr | 2 | 2016-12-02 00:00:00
Petr | 3 | 2016-12-03 00:00:00
Oleg | 3 | 2016-12-01 00:00:00
Oleg | 2 | 2016-12-02 00:00:00
Oleg | 1 | 2016-12-03 00:00:00
I want to get a Output:
name | min | current
Petr | 1 | 3
Oleg | 1 | 1
For to find the maximum, I try
SELECT t1.rank as min
FROM table t1
LEFT JOIN table t2
ON t1.name = t2.name AND t1.rank > t2.rank
WHERE t2.name IS NULL
And other solve, for find the current
SELECT t1.rank as current
FROM table t1
WHERE t1.dt=(SELECT MAX(dt) FROM table t2 WHERE t1.name = t2.name)
I think you are looking for the minimum rating not maximum.
To get current, the rating with max date, use GROUP BY and then join the original table again, to get the rating value for this max date:
SELECT
t1.Name,
MAX(t2.MinRating) AS MinRating,
MAX(t1.Rating) AS Current
FROM yourTable AS t1
INNER JOIN
(
SELECT Name, MIN(rating) AS MinRating, MAX(rateDate) AS MaxRateDate
FROM yourTable
GROUP BY Name
) AS t2 ON t1.Name = t2.Name AND t1.rateDate = t2.MaxRateDate
GROUP BY t1.Name;
fiddle demo
| Name | MinRating | Current |
|------|-----------|---------|
| Oleg | 1 | 1 |
| Petr | 1 | 3 |

Using MAX date to JOIN tables and get column value

I am trying to get the tracking number from a customers most recent order, but I am having trouble using MAX.
This just keeps returning nothing, even though I know table2 has values in there with dates. What's wrong with my query?
SELECT
t1.Invoice_Num,
t1.Tracking_Num
FROM
table1 t1
JOIN
table2 t2a on t1.Invoice_Num = t2a.Invoice_Num
JOIN (
SELECT
t2b.Invoice_Num,
MAX(t2b.Invoice_Date) Last_Sale
FROM
table2 t2b
WHERE
t2b.Customer_Num = 'cust1'
GROUP BY t2b.Invoice_Num
) LS
on t1.Invoice_Num = LS.Invoice_Num
--------------------------------------------------
Table1
+-------------+--------------+
| Invoice_Num | Tracking_Num |
+-------------+--------------+
| abc123 | 12345678 |
| def456 | 87654321 |
+-------------+--------------+
Table2
+-------------+--------------+--------------+
| Invoice_Num | Customer_Num | Invoice_Date |
+-------------+--------------+--------------+
| abc123 | cust1 | 10/25/2017 |
| def456 | cust1 | 10/24/2017 |
+-------------+--------------+--------------+
Desired output is -
+-------------+--------------+
| Invoice_Num | Tracking_Num |
+-------------+--------------+
| abc123 | 12345678 |
+-------------+--------------+
based on the most recent Invoice_Date of cust1
Here's a generic alternative approach that can come in handy:
use ORDER BY .. DESC and LIMIT 1:
SELECT
t1.Invoice_Num,
t1.Tracking_Num
FROM table1 t1
JOIN table2 t2 USING(Invoice_Num)
WHERE t2.Customer_Num = 'cust1'
ORDER BY t2.Invoice_Date DESC
LIMIT 1
SQL Fiddle
SQL DEMO
SELECT
t1.Invoice_Num,
t1.Tracking_Num
FROM table1 t1
JOIN table2 t2
ON t1.Invoice_Num = t2.Invoice_Num
JOIN ( SELECT MAX(t2b.Invoice_Date) Last_Sale
FROM table2 t2b
WHERE t2b.Customer_Num = 'cust1'
) LS
ON t2.Invoice_Date = LS.Last_Sale
Be carefull because if multiple rows share the Last Sale you will get multiple rows.

How to find and take difference in column values in SQL

I am faced with a complicated problem of taking difference in values in rows.
Sales column shows in total sales and it is automatically updated. I would like create a table with column SalesUpdate where it takes the difference in Sales from the two most recent Sales value in TABLE 1.
TABLE 1.
№ | Date | Product | Sales
----------------------------------------
1 | 2017-03-01 | Coke | 10
2 | 2017-03-02 | Pepsi | 9
3 | 2017-03-03 | Tea | 12
4 | 2017-03-04 | Coke | 20
5 | 2017-03-05 | Coke | 22
6 | 2017-03-06 | Pepsi | 15
TABLE 2.
№ | Product | Date | SalesUpdate
---------------------------------------------------------------
1 | Coke | 2017-03-01 | 22-20 = 2
2 | Pepsi | 2017-03-02 | 15-9 = 6
3 | Tea | 2017-03-03 | 12-0 = 12
Not quite elegant solution, but, at least, not DBMS-specific :) Also, didn't get, what data you want to receive in Date column of resulting set.
SELECT md.product,
md.max_Date Date,
(t1.sales - CASE WHEN t2.sales IS NULL THEN 0 ELSE t2.sales END) SalesUpdate
FROM (SELECT MAX(DATE) max_date,
product
FROM TABLE1
GROUP BY PRODUCT) md
INNER JOIN TABLE1 t1 ON md.product = t1.product AND md.max_date = t1.DATE
LEFT JOIN TABLE1 t2 ON t2.product = t1.product AND t2.date < t1.date
LEFT JOIN TABLE1 t3 ON t2.product = t3.product AND t3.date > t2.date AND t3.date < t1.date
WHERE t3.product IS NULL

SQL: join 2 table and change id to username

i have table like this:
table1:
id | item_name | entered_by | modify_by
1 | banana | 2 | 1
2 | apple | 4 | 3
3 | orance | 1 | 1
4 | pineapple | 5 | 3
5 | grape | 6 | 1
table2:
id | username
1 | admin
2 | jack
3 | danny
4 | dummy
5 | john
6 | peter
how do i join these 2 table for table1's entered_by and modify_by is replaced by their username with id correspondingly on table2.
thanks
Try this out:
SELECT t1.id, t1.item_name,
t2enteredBy.username enteredBy,
t2modifyBy.username modifyBy
FROM table1 t1
JOIN table2 t2enteredBy ON t1.entered_by = t2enteredBy.id
JOIN table2 t2modifyBy ON t1.modify_by = t2modifyBy.id
Fiddle here.
In short, you need a join per each of those fields. That's why there is a double join on table2.
SELECT tmp.id, item_name, tmp.username as entered, b.username as modify
FROM (SELECT t.id, item_name, username, modify_by
FROM table1 t
INNER JOIN table2 a
ON t.entered_by=a.id
)tmp
INNER JOIN table2 b ON tmp.modify_by=b.id