MySQL ordering table base on date and another numerical column - mysql

Assume that I have a table like this:
+----+--------------+-----+-----------+
| ID |Date | DD | City |
+----+--------------+-----+-----------+
| 2 | 2016-05-14 | 102 | NY |
| 5 | 2016-05-12 | 101 | London |
| 3 | 2016-05-13 | 101 | Tokyo |
| 6 | 2016-05-12 | 102 | LA |
| 4 | 2016-05-14 | 101 | KC |
| 7 | 2016-05-13 | 102 | Delhi |
+----+--------------+-----+-----------+
How Can I get Sorted result by using MySQL and SQL statements base on Date and DD columns that it be like this:
+----+--------------+-----+-----------+
| ID |Date | DD | City |
+----+--------------+-----+-----------+
| 2 | 2016-05-12 | 101 | NY |
| 5 | 2016-05-12 | 102 | London |
| 3 | 2016-05-13 | 101 | Tokyo |
| 6 | 2016-05-13 | 102 | LA |
| 4 | 2016-05-14 | 101 | KC |
| 7 | 2016-05-14 | 102 | Delhi |
+----+----------+-----+-----------+---+
it means sort table by Date column but each day also sorted by DD.
when I use ORDER BY Date,DD the out put is like this
+----+--------------+-----+-----------+
| ID |Date | DD | City |
+----+--------------+-----+-----------+
| 2 | 2016-05-12 | 101 | NY |
| 5 | 2016-05-13 | 101 | London |
| 3 | 2016-05-14 | 101 | Tokyo |
| 6 | 2016-05-12 | 102 | LA |
| 4 | 2016-05-13 | 102 | KC |
| 7 | 2016-05-14 | 102 | Delhi |
+----+----------+-----+-----------+---+
this is not true for me.

SELECT * FROM `table` ORDER BY `Date`,`DD`

SELECT * FROM table ORDER BY Date ASC,DD DESC

Related

Is there a mySQL procedure that can merge duplicate rows of data into one, then allow me to manipulate that data as if it were one row?

I'm trying to come up with a stored procedure that takes multiple rows that are exactly identical, and combines them into one row while summing one column, which can then be run through more stored procedures based on the sum of that one column.
I've tried a GROUP BY statement, but that doesn't actually group the rows together, because if I run the table through another procedure it performs actions as if each row were not combined. Performing a SELECT * FROM mytable query shows that each row was not actually combined into one.
Is there any way to permanently combine multiple rows into one singular row?
To start, I've got a table like this:
+-------+-----+--------+---------+------+-----+-----------+
| RowID | pID | Name | Date | Code | QTY | Purchased |
+-------+-----+--------+---------+------+-----+-----------+
| 1 | 1 | bob | 9/29/20 | 123 | 1 | |
| 2 | 1 | bob | 8/10/20 | 456 | 1 | |
| 3 | 2 | rob | 9/15/20 | 123 | 1 | |
| 4 | 2 | rob | 9/15/20 | 123 | 1 | |
| 5 | 2 | rob | 9/15/20 | 123 | 1 | |
| 6 | 2 | rob | 9/15/20 | 123 | 1 | |
| 7 | 2 | rob | 9/15/20 | 123 | 1 | |
| 8 | 3 | john | 7/12/20 | 987 | 1 | |
| 9 | 3 | john | 7/12/20 | 987 | 1 | |
| 10 | 4 | george | 9/12/20 | 684 | 1 | |
| 11 | 5 | paul | 2/2/20 | 454 | 1 | |
| 12 | 6 | amy | 1/12/20 | 252 | 1 | |
| 13 | 7 | susan | 5/30/20 | 131 | 1 | |
| 14 | 7 | susan | 6/6/20 | 252 | 1 | |
| 15 | 7 | susan | 5/30/20 | 131 | 1 | |
+-------+-----+--------+---------+------+-----+-----------+
By the end, i'd like to have a table like this:
+-------+-----+--------+---------+------+-----+-----------+
| RowID | pID | Name | Date | Code | QTY | Purchased |
+-------+-----+--------+---------+------+-----+-----------+
| 1 | 1 | bob | 9/29/20 | 123 | 1 | |
| 2 | 1 | bob | 8/10/20 | 456 | 1 | |
| 3 | 2 | rob | 9/15/20 | 123 | 5 | |
| 4 | 3 | john | 7/12/20 | 987 | 2 | |
| 5 | 4 | george | 9/12/20 | 684 | 1 | |
| 6 | 5 | paul | 2/2/20 | 454 | 1 | |
| 7 | 6 | amy | 1/12/20 | 252 | 1 | |
| 8 | 7 | susan | 5/30/20 | 131 | 2 | |
| 9 | 7 | susan | 6/6/20 | 252 | 1 | |
+-------+-----+--------+---------+------+-----+-----------+
Where exactly identical rows are combined into one row, and the QTY field is summed, that I can then add purchases to, or make deductions from the quantity as a total. Using GROUP BY statements can achieve this, but when I go to alter the quantity or add purchases to each person, it treats it like the first table, as if nothing was actually grouped.
So you have this table:
| RowID | pID | Name | Date | Code | QTY | Purchased |
+-------+-----+--------+---------+------+-----+-----------+
| 1 | 1 | bob | 9/29/20 | 123 | 1 | |
| 2 | 1 | bob | 8/10/20 | 456 | 1 | |
| 3 | 2 | rob | 9/15/20 | 123 | 1 | |
| 4 | 2 | rob | 9/15/20 | 123 | 1 | |
| 5 | 2 | rob | 9/15/20 | 123 | 1 | |
| 6 | 2 | rob | 9/15/20 | 123 | 1 | |
| 7 | 2 | rob | 9/15/20 | 123 | 1 | |
| 8 | 3 | john | 7/12/20 | 987 | 1 | |
| 9 | 3 | john | 7/12/20 | 987 | 1 | |
| 10 | 4 | george | 9/12/20 | 684 | 1 | |
| 11 | 5 | paul | 2/2/20 | 454 | 1 | |
| 12 | 6 | amy | 1/12/20 | 252 | 1 | |
| 13 | 7 | susan | 5/30/20 | 131 | 1 | |
| 14 | 7 | susan | 6/6/20 | 252 | 1 | |
| 15 | 7 | susan | 5/30/20 | 131 | 1 | |
The best way, as has been suggested, is to create a new table with the content of your query, then to rename the old table, and the new table to the original table's name, to check if everything is all right, and to drop the original table if yes.
CREATE TABLE indata_new AS
WITH grp AS (
SELECT
MIN(rowid) AS orowid
, pid
, name
, MAX(date) AS date
, code
, SUM(qty) AS qty
FROM indata
GROUP BY
pid
, name
, code
)
SELECT
ROW_NUMBER() OVER(ORDER BY orowid ASC) AS rowid
, *
FROM grp;
ALTER TABLE indata RENAME TO indata_old;
ALTER TABLE indata_new RENAME TO indata;
-- if "indata" now contains the data you want ...
SELECT * FROM indata;
-- out rowid | orowid | pid | name | date | code | qty
-- out -------+--------+-----+--------+------------+------+-----
-- out 1 | 1 | 1 | bob | 2020-09-29 | 123 | 1
-- out 2 | 2 | 1 | bob | 2020-08-10 | 456 | 1
-- out 3 | 3 | 2 | rob | 2020-09-15 | 123 | 5
-- out 4 | 8 | 3 | john | 2020-07-12 | 987 | 2
-- out 5 | 10 | 4 | george | 2020-09-12 | 684 | 1
-- out 6 | 11 | 5 | paul | 2020-02-02 | 454 | 1
-- out 7 | 12 | 6 | amy | 2020-01-12 | 252 | 1
-- out 8 | 13 | 7 | susan | 2020-05-30 | 131 | 2
-- out 9 | 14 | 7 | susan | 2020-06-06 | 252 | 1
-- you can ...
DROP TABLE indata_old;

Query the differences between records with same ID

I have a table like this in MS Access 2019:
+-----------+------------+--------+----------+-------+
| BillingID | Date | RoomID | Electric | Water |
+-----------+------------+--------+----------+-------+
| 1 | 12/23/2018 | 4 | 1669 | 106 |
| 2 | 12/26/2018 | 1 | 5035 | 289 |
| 3 | 12/27/2018 | 6 | 0 | 0 |
| 4 | 12/31/2018 | 5 | 3158 | 223 |
| 5 | 1/6/2019 | 2 | 3823 | 194 |
| 6 | 1/15/2019 | 3 | 1772 | 125 |
| 7 | 1/23/2019 | 4 | 1796 | 117 |
| 8 | 1/26/2019 | 1 | 5231 | 299 |
| 9 | 1/27/2019 | 6 | 0 | 0 |
| 10 | 1/31/2019 | 5 | 3366 | 242 |
| 11 | 2/14/2019 | 2 | 3975 | 201 |
| 12 | 2/15/2019 | 3 | 1839 | 129 |
+-----------+------------+--------+----------+-------+
I could calculate the electricity and water usage with Index & Match in MS Excel. However, I've had a lot of trouble to achieve this with MS Access. The result I want is as below:
+-----------+------------+--------+----------+---------------+-------+------------+
| BillingID | Date | RoomID | Electric | ElectricUsage | Water | WaterUsage |
+-----------+------------+--------+----------+---------------+-------+------------+
| 1 | 12/23/2018 | 4 | 1669 | | 106 | |
| 2 | 12/26/2018 | 1 | 5035 | | 289 | |
| 3 | 12/27/2018 | 6 | 0 | | 0 | |
| 4 | 12/31/2018 | 5 | 3158 | | 223 | |
| 5 | 1/6/2019 | 2 | 3823 | | 194 | |
| 6 | 1/15/2019 | 3 | 1772 | | 125 | |
| 7 | 1/23/2019 | 4 | 1796 | 127 | 117 | 11 |
| 8 | 1/26/2019 | 1 | 5231 | 196 | 299 | 10 |
| 9 | 1/27/2019 | 6 | 0 | | 0 | |
| 10 | 1/31/2019 | 5 | 3366 | 208 | 242 | 19 |
| 11 | 2/14/2019 | 2 | 3975 | 152 | 201 | 7 |
| 12 | 2/15/2019 | 3 | 1839 | 67 | 129 | 4 |
+-----------+------------+--------+----------+---------------+-------+------------+
For example, for RoomID = 4, the ElectricUsage is the difference between the Electric in BillingID #7 and BillingID #1 and so on.
I've tried some answer like this or this but Access ran into errors when using those solutions in SQL view (Syntax error in FROM clause).
Thanks.
You can use a couple of sub-queries to return the Electric/Water for each room on the previous date:
SELECT
B.BillingID, B.BillingDate, B.RoomID, B.Electric,
B.Electric-(SELECT TOP 1 E.Electric FROM tblBilling AS E WHERE B.RoomID=E.RoomID AND E.BillingDate<B.BillingDate ORDER BY E.BillingDate DESC) AS ElectricUsage,
B.Water,
B.Water-(SELECT TOP 1 W.Water FROM tblBilling AS W WHERE B.RoomID=W.RoomID AND W.BillingDate<B.BillingDate ORDER BY W.BillingDate DESC) AS WaterUsage
FROM tblBilling AS B
Note that I've renamed your Date field to be BillingDate, as Date is a reserved word in Access, and will cause you problems in the future.
Regards,

How to subtract the sum of value using left join?

I have two tables orders and customers:
select * from orders;
+------+---------------------+-------------+--------+
| oid | date | customer_id | amount |
+------+---------------------+-------------+--------+
| 102 | 2009-10-08 00:00:00 | 4 | 300 |
| 100 | 2009-10-08 00:00:00 | 3 | 15000 |
| 101 | 2008-10-08 00:00:00 | 2 | 1300 |
| 105 | 2010-10-08 00:00:00 | 1 | 400 |
| 106 | 2014-12-23 00:00:00 | 3 | 300 |
+------+---------------------+-------------+--------+
select * from customers;
+------+--------+------+-----------+----------+
| id | name | age | address | salary |
+------+--------+------+-----------+----------+
| 1 | ramesh | 32 | Ahmedabad | 2000.00 |
| 2 | khilan | 25 | delhi | 1500.00 |
| 3 | muffy | 22 | bhopal | 8500.00 |
| 4 | suresh | 48 | mumbai | 24000.00 |
| 1 | ramesh | 32 | Ahmedabad | 300.00 |
| 5 | akil | 21 | madurai | 1000.00 |
| 6 | rajesh | 22 | delhi | 5000.00 |
+------+--------+------+-----------+----------+
What I'm trying to do is to do SUM(salary) from customers and subtract it with the SUM(amount) from orders table. I have tried with this query:
SELECT id ,NAME,SUM(salary),SUM(amount),SUM(salary)-SUM(amount)
FROM customers a LEFT JOIN orders b ON a.id=b.customer_id
GROUP BY NAME;
This will return the following result, which some of them return incorrect value:
+------+--------+-------------+-------------+-------------------------+
| id | name | SUM(salary) | SUM(amount) | SUM(salary)-SUM(amount) |
+------+--------+-------------+-------------+-------------------------+
| 5 | akil | 1000.00 | NULL | NULL |
| 2 | khilan | 1500.00 | 1300 | 200.00 |
| 3 | muffy | 17000.00 | 15300 | 1700.00 |
| 6 | rajesh | 5000.00 | NULL | NULL |
| 1 | ramesh | 2300.00 | 800 | 1500.00 |
| 4 | suresh | 24000.00 | 300 | 23700.00 |
+------+--------+-------------+-------------+-------------------------+
My expected output is as following:
+------+--------+-------------+-------------+-------------------------+
| id | name | SUM(salary) | SUM(amount) | SUM(salary)-SUM(amount) |
+------+--------+-------------+-------------+-------------------------+
| 5 | akil | 1000.00 | NULL | 1000 |
| 2 | khilan | 1500.00 | 1300 | 200.00 |
| 3 | muffy | 8500 | 15300 | -6800 |
| 6 | rajesh | 5000.00 | NULL | 5000 |
| 1 | ramesh | 2300.00 | 400 | 1900.00 |
| 4 | suresh | 24000.00 | 300 | 23700.00 |
+------+--------+-------------+-------------+-------------------------+
One way is to make calculation on orders into sub-query.
To cater for NULL value, you can use IFNULL(value,0).
SELECT id,NAME,SUM(salary),amt,SUM(salary)-IFNULL(amt,0)
FROM customers a LEFT JOIN
(SELECT customer_id, SUM(amount) amt FROM orders GROUP BY customer_id) b
ON a.id=b.customer_id
GROUP BY NAME;

Select within select subquery takes too long

I have 3 tables :
60.000 record Invoice
100.000 record Exchange Rate based on current date
25 record Currency Symbol
table_invoice:
+-----------+-------------+----------+--------------+
| invoice_id | currency_id | amount | invoice_date |
+------------+-------------+----------+--------------+
| 1 | 2 | 10 | 4/28/2016 |
| 2 | 3 | 30 | 4/29/2016 |
| 3 | 4 | 50 | 4/30/2016 |
| 4 | 2 | 40 | 6/18/2016 |
| 5 | 6 | 25 | 6/20/2016 |
| 6 | 7 | 87 | 6/25/2016 |
| 7 | 4 | 100 | 6/29/2016 |
| 8 | 9 | 45 | 7/14/2016 |
| 9 | 2 | 71 | 9/27/2016 |
| 60000 | 3 | 430 | 1/18/2017 |
+------------+-------------+----------+--------------+
and
table_exchange_rate:
+-----------------+-------------+---------------+--------------------+
| exchange_rate_id | currency_id | exchange_rate | exchange_rate_date |
+------------------+-------------+---------------+--------------------+
| 1 | 2 | 13.352 | 4/25/2016 |
| 2 | 3 | 10.195 | 4/25/2016 |
| 3 | 4 | 14.390 | 4/25/2016 |
| 4 | 5 | 1.720 | 4/25/2016 |
| 5 | 6 | 118 | 4/25/2016 |
| 6 | 7 | 9.468 | 4/25/2016 |
| 7 | 2 | 13.125 | 6/15/2016 |
| 8 | 3 | 10.520 | 6/25/2016 |
| 9 | 4 | 14.800 | 6/25/2016 |
| 10 | 5 | 1.800 | 6/25/2016 |
| 11 | 6 | 120 | 6/25/2016 |
| 12 | 7 | 9.320 | 6/25/2016 |
| 100000 | 7 | 9.500 | 6/25/2016 |
+------------------+-------------+---------------+--------------------+
and
reference_currency:
+-----------------+---------------+-----------------------+
| currency_id |currency_symbol| currency_name |
+------------------+---------------+-----------------------+
| 1 | USD | US Dollar |
| 2 | AUD | Australian Dollar |
| 3 | EUR | Euro |
| 4 | HKD | Hong Kong Dollar |
| 5 | JPY | Japan Yen |
| 6 | SGD | Singapore Dollar |
| 7 | MYR | Malaysian Ringgit |
| 8 | CHF | Swiss Franc |
| 9 | THB | Thailand Baht |
| 10 | GBP | Great Britain Pounds |
| 11 | SEK | Swedish Krona |
| 12 | CNY | China Yuan |
| 25 | SAR | Saudi Arabian Riyal |
+------------------+-------------+-------------------------+
When I run:
SELECT
a.invoice_id AS 'INVOICE_ID',
a.currency_id AS 'CURRENCY_ID',
a.amount AS 'AMOUNT',
a.invoice_date AS 'INVOICE_DATE',
(
SELECT b.exchange_rate FROM table_exchange_rate b
WHERE b.exchange_rate_date <= a.invoice_date AND b.currency_id = a.currency_id
ORDER BY b.exchange_rate_date DESC LIMIT 1) AS 'EXCHANGE RATE'
)
FROM table_invoice a
Result:
`+------------+-------------+----------+--------------+--------------+
| INVOICE_ID | CURRENCY_ID | AMOUNT | INVOICE_DATE | EXCHANGE_RATE |
+------------+-------------+----------+--------------+---------------+
| 1 | 2 | 10 | 4/28/2016 | 13.352
| 2 | 3 | 30 | 4/29/2016 | 10.195
| 3 | 4 | 50 | 4/30/2016 | 14.390
| 4 | 2 | 40 | 6/18/2016 | 13.125
| 5 | 6 | 25 | 6/20/2016 | 118
| 6 | 7 | 87 | 6/25/2016 | 9.320
`
and the result works fine but it is very slow(approximately > 60sec) with 60k record(table_invoice) looping on 100k record(table_exchange_rate) finding exchange rate at the current date,
If invoice_date can't match with exchange_rate_date or the user doesn't input the exchange rate on the app, it will using exchange rate the latest record already in input before the current date (b.exchange_rate_date <= a.invoice_date AND b.currency_id = a.currency_id)
Can I speed up this query or there any other options? Thank you..
Try same thing with JOIN
select a.invoice 'invoice_id', a.currency_id 'curency_id', a.amount 'amount', a.invoice_date 'invoice_date', ter.exchange_rate ' exchange_rate'
from table_invoice ti
left join table_exchange_rate ter on ter.currency_id = ti.currency_id and ter.exchange_rate_date <= ti.invoice_date

SQL joining three tables and split into columns

I have three tables, mess_stock, mess_voucher, add_grocery.
Mess_stock table is below,
+-----+------------+-----------------+-----------------+--------+---------+---------+------------+----------+
| sno | voucher_id | particular_name | opening_balance | inward | outward | balance | pay_amount | pay_type |
+-----+------------+-----------------+-----------------+--------+---------+---------+------------+----------+
| 49 | 5 | 4 | 100 | 10 | 100 | 10 | 10.00 | 1 |
| 50 | 17 | 5 | 111 | 10 | 20 | 101 | 60.00 | 1 |
| 51 | 7 | 3 | 123 | 2 | 1 | 124 | 300.00 | 1 |
| 52 | 7 | 1 | 123 | 20 | 20 | 123 | 500.00 | 2 |
| 53 | 14 | 8 | 100 | 5 | 95 | 10 | 60.00 | 2 |
+-----+------------+-----------------+-----------------+--------+---------+---------+------------+----------+
Mess_voucher table is below
+------------+--------------+--------------+
| voucher_id | voucher_name | voucher_date |
+------------+--------------+--------------+
| 5 | VG1001 | 2015-02-19 |
| 6 | VG1001 | 2015-02-20 |
| 7 | VG1002 | 2015-02-20 |
| 8 | VG1002 | 2015-02-19 |
| 9 | MS1001 | 2015-02-20 |
| 10 | VG10012 | 2015-02-19 |
| 11 | 0 | 2015-02-23 |
| 12 | 1 | 2015-02-24 |
| 13 | MS1001 | 2015-02-25 |
| 14 | MS1001 | 2015-02-28 |
| 15 | VG1003 | 2015-02-28 |
| 16 | MS1001 | 2015-02-19 |
| 17 | MS1001 | 2015-02-21 |
+------------+--------------+--------------+
Add_grocery table is below
+-----+-----------------+------------------+
| sno | particular_name | particular_price |
+-----+-----------------+------------------+
| 1 | Rice | 25.00 |
| 3 | Mango | 150.00 |
| 4 | Coconut | 22.00 |
| 5 | Banana | 6.00 |
| 6 | Raddish | 12.00 |
| 7 | Apple | 150.00 |
| 8 | Pumkin | 12.00 |
+-----+-----------------+------------------+
I want to group the sum of pay_amount of mess_stock table. I have used the below query
SELECT opening_balance AS ope_stock,
balance AS clo_stock,
SUM(IF(pay_type = 1, pay_amount, 0)) mess_pay,
SUM(IF(pay_type=2, pay_amount, 0)) est_pay
FROM mess_stock;
That works fine. The particular_name is the auto increment id of add_grocery table. I need the inward outward amount total. For example the inward amount 10 means it has to get the particular_price from add_grocery using the particular_name provided in the mess_stock table, similarly I need all the answer. And I want to sort that by date wise. The date of the entry is stored in the mess_voucher table that is connected to mess_stock table.
Try this it will work :
Use Inner Join :
SELECT t2.`particular_name`,t1.`inward`,t1.`outward`,t2.`particular_price`,t3.`voucher_date` from Mess_stock t1 JOIN Add_grocery t2 ON t1.`particular_name`=t2.`sno` JOIN Mess_voucher t3 ON t3.`voucher_id`=t1.`voucher_id` ORDER BY t3.`voucher_date` DESC