MySQL get running difference for unique titles with date - mysql

I have some data in MySQL table. Its primary key is domain name and tstamp (date). This table is updated just once a week. Now I want to get a difference of one domain in consecutive weeks on UrduCount column.
Following is the table sample data (for just three weeks but will grow in future)
mysql> select * from domainStats order by domain_name limit 10;
+-----------------------+------------+---------+------------+------------+-----------+------------+------+
| domain_name | TotalLinks | Succeed | NotSucceed | NotFetched | UrduCount | tstamp | src |
+-----------------------+------------+---------+------------+------------+-----------+------------+------+
| 107.170.52.240 | 59574 | 30226 | 1688 | 27660 | 60000 | 2019-10-04 | use2 |
| 107.170.52.240 | 59027 | 30315 | 1689 | 27023 | 40000 | 2019-09-27 | use2 |
| 107.170.52.240 | 59027 | 30315 | 1689 | 27023 | 10000 | 2019-09-20 | use2 |
| www.dunyapakistan.com | 66542 | 20608 | 4844 | 41090 | 30000 | 2019-10-04 | use2 |
| www.dunyapakistan.com | 66542 | 20608 | 4844 | 41090 | 30000 | 2019-09-27 | use2 |
| www.dunyapakistan.com | 65380 | 20192 | 5293 | 39895 | 20000 | 2019-09-20 | use2 |
| www.urdupoint.com | 129751 | 20746 | 494 | 108511 | 50000 | 2019-10-04 | use2 |
| www.urdupoint.com | 129751 | 20746 | 494 | 108511 | 50000 | 2019-09-27 | use2 |
| www.urdupoint.com | 126879 | 20779 | 455 | 105645 | 10000 | 2019-09-20 | use2 |
+-----------------------+------------+---------+------------+------------+-----------+------------+------+
Expected out similar to following (consecutive difference of same domains in consecutive weeks)
www.urdupoint.com | 2019-10-04 | 20000
www.urdupoint.com | 2019-09-27 | 30000
www.urdupoint.com | 2019-09-20 | 10000
...

In MySQL 5.x you can use a correlated sub-query:
SELECT domain_name, tstamp, UrduCount - COALESCE((
SELECT UrduCount
FROM t AS x
WHERE x.domain_name = t.domain_name
AND x.tstamp < t.tstamp
ORDER BY x.tstamp DESC
LIMIT 1
), 0) AS diff
FROM t
In MySQL 8 or later you could simply use the LAG function.

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;

Mysql Finding Aggregate Between Two Other Values

I'm working with a pretty nasty table schema which unfortunately I can't change as it's defined by our SCADA program. There's one analog float value (power usage), and one digital int value (machine setting). I need to be able to find the Min, Max, and Avg of the power usage for each machine setting.
So basically each time a new machine setting (intvalue) is recorded, I need the aggregate power usage (floatvalue) until the next machine setting. I'd like to be able to group by intvalue as well, so I could get these aggregate numbers for a whole month, for example.
So far, I've tried playing around with joins and nested queries, but I can't get anything to work. I can't really find any examples like this either, since its such a poor table design.
Table schema found here: http://www.sqlfiddle.com/#!9/29164/1
Data:
| tagid | intvalue | floatvalue | t_stamp |
|-------|----------|------------|----------------------|
| 2 | 9 | (null) | 2019-07-01T00:01:58Z |
| 1 | (null) | 120.2 | 2019-07-01T00:02:00Z |
| 1 | (null) | 120.1 | 2019-07-01T00:02:31Z |
| 2 | 11 | (null) | 2019-07-01T00:07:58Z |
| 1 | (null) | 155.9 | 2019-07-01T00:08:00Z |
| 1 | (null) | 175.5 | 2019-07-01T00:10:12Z |
| 1 | (null) | 185.5 | 2019-07-01T00:10:58Z |
| 2 | 2 | (null) | 2019-07-01T00:11:22Z |
| 1 | (null) | 10.1 | 2019-07-01T00:11:22Z |
| 1 | (null) | 12 | 2019-07-01T00:13:58Z |
| 1 | (null) | 9.9 | 2019-07-01T00:14:21Z |
| 2 | 9 | (null) | 2019-07-01T00:15:38Z |
| 1 | (null) | 120.9 | 2019-07-01T00:15:39Z |
| 1 | (null) | 119.2 | 2019-07-01T00:16:22Z |
Desired output:
| intvalue | min | avg | max |
|----------|-------|-------|-------|
| 2 | 9.9 | 10.7 | 12 |
| 9 | 119.2 | 120.1 | 120.9 |
| 11 | 155.9 | 172.3 | 185.5 |
Is this possible?
You can fill the missing intvalues with a subquery in the SELECT clause:
select t.*, (
select t1.intvalue
from sqlt_data_1_2019_07 t1
where t1.t_stamp <= t.t_stamp
and t1.intvalue is not null
order by t1.t_stamp desc
limit 1
) as group_int
from sqlt_data_1_2019_07 t
order by t.t_stamp;
The result will be
| tagid | intvalue | floatvalue | t_stamp | group_int |
| ----- | -------- | ---------- | ------------------- | --------- |
| 2 | 9 | | 2019-07-01 00:01:58 | 9 |
| 1 | | 120.2 | 2019-07-01 00:02:00 | 9 |
| 1 | | 120.1 | 2019-07-01 00:02:31 | 9 |
| 2 | 11 | | 2019-07-01 00:07:58 | 11 |
| 1 | | 155.9 | 2019-07-01 00:08:00 | 11 |
| 1 | | 175.5 | 2019-07-01 00:10:12 | 11 |
| 1 | | 185.5 | 2019-07-01 00:10:58 | 11 |
| 2 | 2 | | 2019-07-01 00:11:22 | 2 |
| 1 | | 10.1 | 2019-07-01 00:11:22 | 2 |
| 1 | | 12 | 2019-07-01 00:13:58 | 2 |
| 1 | | 9.9 | 2019-07-01 00:14:21 | 2 |
| 2 | 9 | | 2019-07-01 00:15:38 | 9 |
| 1 | | 120.9 | 2019-07-01 00:15:39 | 9 |
| 1 | | 119.2 | 2019-07-01 00:16:22 | 9 |
Now you can simply group by the result of the subquery:
select (
select t1.intvalue
from sqlt_data_1_2019_07 t1
where t1.t_stamp <= t.t_stamp
and t1.intvalue is not null
order by t1.t_stamp desc
limit 1
) as group_int,
min(floatvalue) as min,
avg(floatvalue) as avg,
max(floatvalue) as max
from sqlt_data_1_2019_07 t
group by group_int
order by group_int;
And you get:
| group_int | min | avg | max |
| --------- | ----- | ------------------ | ----- |
| 2 | 9.9 | 10.666666666666666 | 12 |
| 9 | 119.2 | 120.10000000000001 | 120.9 |
| 11 | 155.9 | 172.29999999999998 | 185.5 |
View on DB Fiddle

Group_Concat() is not working properly in mysql

I have three tables :
em_employee :
emp_number | emp_firstname |
+------------+---------------+
| 1 | Vikram |
| 2 | S. |
| 3 | Gopal |
| 4 | Vaishnavi |
| 5 | Srinivasan |
| 6 | Saravanan
em_project
+------------+------------------------------+
| project_id | name |
+------------+------------------------------+
| 339 | MoneyGram |
| 340 | SERVICE LINE HEAD COMPLIANCE |
| 341 | SERVICE LINE HEAD ANALYTICS |
| 342 | GSI |
| 343 | Tandem |
| 344 | Master Card |
+------------+------------------------------+
em_project_employee:
+------------+------------+
| emp_number | project_id |
+------------+------------+
| 1 | 339 |
| 2 | 340 |
| 3 | 341 |
| 4 | 342 |
| 1 | 343 |
| 6 | 344 |
| 2 | 342 |
+------------+------------+
And I want Output like :
+------------+----------------------------------+
| emp_number | name |
+------------+----------------------------------+
| 1 | MoneyGram , Tandem |
| 2 | SERVICE LINE HEAD COMPLIANCE,GSI |
| 3 | SERVICE LINE HEAD ANALYTICS |
| 4 | GSI |
| 6 | Master Card |
+------------+----------------------------------+
I have tried it with GROUP_CONCAT, but something going wrong. Please help me on this.
Try this query, it produes that output:
SELECT emp_number, GROUP_CONCAT(name) FROM em_project p
INNER JOIN em_project_employee em ON p.project_id = em.project_id
GROUP BY emp_number;
The order of the data will e slightly different from what's in your desired output. If the ordering is important.
GROUP_CONCAT(name ORDER BY p.project_id)

MySQL SUM() returning spurious (?) values

Despite spending an hour on this, the solution is eluding me still. I have a complex-ish query that is returning incorrect data for the SUM(). Yet, when I strip it down to the barest form, it outputs the correct data. But why and fix, I cannot figure out.
The Problem
SELECT po.*, SUM( poo.material_qty ) AS total_items_ordered, suppliers.supplier_name
FROM `purchase_orders` po
LEFT JOIN purchase_orders_items poo ON poo.poid = po.poid
LEFT JOIN suppliers ON suppliers.supplier_id = po.supplier_id
LEFT JOIN materials_batch mb ON mb.purchase_order_no = po.poid
WHERE po_status NOT
IN (
'Fulfilled', 'Cancelled'
)
AND batch_status NOT
IN (
'Arrived', 'Cancelled', 'Refused', 'Missing', 'Damaged', 'Completed'
)
GROUP BY po.poid
ORDER BY date_expected ASC
Provides wildly incorrect data for 'total_items_ordered'.
+-------+---------------------+---------------------+-------------+--------+-------------+--------+-----------+---------+----------+--------+----+--------+-----------+---------------------+-----------------------+
| poid | date_raised | date_expected | supplier_id | job_id | job_item_id | ref_no | sub_total | VAT | total | userid | DN | manual | po_status | total_items_ordered | supplier_name |
+-------+---------------------+---------------------+-------------+--------+-------------+--------+-----------+---------+----------+--------+----+--------+-----------+---------------------+-----------------------+
| 15571 | 2014-06-24 13:32:55 | 2014-06-25 00:00:00 | 1 | 0 | 0 | | 14850.10 | 2970.02 | 17820.12 | 1 | | N | Raised | 545 | John Parker & Son Ltd |
| 15572 | 2014-06-24 13:33:26 | 2014-06-25 00:00:00 | 1 | 0 | 0 | | 997.80 | 199.56 | 1197.36 | 1 | | N | Raised | 80 | John Parker & Son Ltd |
+-------+---------------------+---------------------+-------------+--------+-------------+--------+-----------+---------+----------+--------+----+--------+-----------+---------------------+-----------------------+
2 rows in set (0.00 sec)
And yet, when I strip all the complexities out of the query and run the raw SUM(), the value is correct:
mysql> SELECT poid, SUM(material_qty) AS total_items_ordered FROM `purchase_orders_items` GROUP BY poid;
+-------+---------------------+
| poid | total_items_ordered |
+-------+---------------------+
| 15571 | 109 |
| 15572 | 20 |
+-------+---------------------+
2 rows in set (0.00 sec)
Can anyone shed any light on where I'm going wrong here?? I've included all the test table content below just in case you can spot something I've missed. Thank you!
Data Example
mysql> SELECT * FROM purchase_orders;
+-------+---------------------+---------------------+-------------+--------+-------------+--------+-----------+---------+----------+--------+----+--------+-----------+
| poid | date_raised | date_expected | supplier_id | job_id | job_item_id | ref_no | sub_total | VAT | total | userid | DN | manual | po_status |
+-------+---------------------+---------------------+-------------+--------+-------------+--------+-----------+---------+----------+--------+----+--------+-----------+
| 15571 | 2014-06-24 13:32:55 | 2014-06-25 00:00:00 | 1 | 0 | 0 | | 14850.10 | 2970.02 | 17820.12 | 1 | | N | Raised |
| 15572 | 2014-06-24 13:33:26 | 2014-06-25 00:00:00 | 1 | 0 | 0 | | 997.80 | 199.56 | 1197.36 | 1 | | N | Raised |
+-------+---------------------+---------------------+-------------+--------+-------------+--------+-----------+---------+----------+--------+----+--------+-----------+
2 rows in set (0.00 sec)
mysql> SELECT * FROM purchase_orders_items;
+--------+-------+-------------+--------------+----------------+--------------+--------------------------------------------------+
| poi_id | poid | material_id | material_qty | material_price | material_sku | material_name |
+--------+-------+-------------+--------------+----------------+--------------+--------------------------------------------------+
| 1 | 15571 | 2 | 3 | 100.00 | PKS275282 | 406x140 White Universal Beam (S355) |
| 2 | 15571 | 5 | 10 | 17.40 | 118-64-44 | Test Item (S275) |
| 3 | 15571 | 8 | 1 | 9984.50 | 113-64-21 | A really really really big universal beam (S355) |
| 4 | 15571 | 9 | 77 | 10.00 | 12345 | A thing |
| 5 | 15571 | 10 | 18 | 201.20 | 12-34-56 | 102x230 Narrow Beam (S355) |
| 6 | 15572 | 2 | 6 | 100.00 | PKS275282 | 406x140 White Universal Beam (S355) |
| 7 | 15572 | 5 | 9 | 17.40 | 118-64-44 | Test Item (S275) |
| 8 | 15572 | 9 | 4 | 10.00 | 12345 | A thing |
| 9 | 15572 | 10 | 1 | 201.20 | 12-34-56 | 102x230 Narrow Beam (S355) |
+--------+-------+-------------+--------------+----------------+--------------+--------------------------------------------------+
9 rows in set (0.00 sec)
mysql> SELECT * FROM suppliers;
+-------------+-----------------------+--------------------+--------------+---------------------+-------------------+-----------------------+--------------------------+---------------------+----------------------+
| supplier_id | supplier_name | supplier_telephone | supplier_fax | supplier_added_date | supplier_added_by | supplier_last_updated | supplier_last_updated_by | supplier_assessed | supplier_approved_by |
+-------------+-----------------------+--------------------+--------------+---------------------+-------------------+-----------------------+--------------------------+---------------------+----------------------+
| 1 | John Parker & Son Ltd | 01227 783333 | 0800 521932 | 2014-05-04 15:57:43 | 1 | 2014-06-05 16:38:23 | 1 | 2014-05-04 15:57:43 | 2 |
| 2 | Superior Glass Ltd. | 01825 764766 | 01825 767699 | 2014-05-04 17:48:38 | 1 | 2014-06-04 20:14:16 | 1 | 2014-05-04 17:48:38 | 3 |
| 3 | DTS Origins Ltd. | 01283 3283029 | 01928 303494 | 2014-05-04 17:51:57 | 1 | 2014-05-04 17:53:08 | 1 | 2014-05-04 17:51:57 | 2 |
+-------------+-----------------------+--------------------+--------------+---------------------+-------------------+-----------------------+--------------------------+---------------------+----------------------+
3 rows in set (0.00 sec)
mysql> SELECT * FROM materials_batch;
+-------------------+-------+---------------------+-------------------+------------------+-----+---------+------------+-------------+-------------+--------------+
| material_batch_id | poiid | rcvd_date | purchase_order_no | delivery_note_no | qty | rcvd_by | dn_scanned | material_id | supplier_id | batch_status |
+-------------------+-------+---------------------+-------------------+------------------+-----+---------+------------+-------------+-------------+--------------+
| 1 | 1 | 0000-00-00 00:00:00 | 15571 | | 3 | 0 | No | 2 | 1 | Ordered |
| 2 | 2 | 0000-00-00 00:00:00 | 15571 | | 10 | 0 | No | 5 | 1 | Ordered |
| 3 | 3 | 0000-00-00 00:00:00 | 15571 | | 1 | 0 | No | 8 | 1 | Ordered |
| 4 | 4 | 0000-00-00 00:00:00 | 15571 | | 77 | 0 | No | 9 | 1 | Ordered |
| 5 | 5 | 0000-00-00 00:00:00 | 15571 | | 18 | 0 | No | 10 | 1 | Ordered |
| 6 | 6 | 0000-00-00 00:00:00 | 15572 | | 6 | 0 | No | 2 | 1 | Ordered |
| 7 | 7 | 0000-00-00 00:00:00 | 15572 | | 9 | 0 | No | 5 | 1 | Ordered |
| 8 | 8 | 0000-00-00 00:00:00 | 15572 | | 4 | 0 | No | 9 | 1 | Ordered |
| 9 | 9 | 0000-00-00 00:00:00 | 15572 | | 1 | 0 | No | 10 | 1 | Ordered |
+-------------------+-------+---------------------+-------------------+------------------+-----+---------+------------+-------------+-------------+--------------+
The reason for the wrong results should be clear when you leave out the GROUP BY from your query. For each table you JOIN, the number of returned rows is multiplied by the number of rows found by the JOIN.
As the materials_batch table contains multiple entries per order, the resulting total_items_ordered is multiplied by 5 for order number 15571, and its multiplied by 4 for order number 15572.
Try the following:
SELECT
po.*,
(
SELECT SUM(poo.material_qty)
FROM purchase_orders_items poo
WHERE poo.poid = po.poid
) AS total_items_ordered,
suppliers.supplier_name
FROM `purchase_orders` po
LEFT JOIN suppliers ON suppliers.supplier_id = po.supplier_id
LEFT JOIN materials_batch mb ON mb.purchase_order_no = po.poid
WHERE po_status NOT
IN (
'Fulfilled', 'Cancelled'
)
AND batch_status NOT
IN (
'Arrived', 'Cancelled', 'Refused', 'Missing', 'Damaged', 'Completed'
)
GROUP BY po.poid
ORDER BY date_expected ASC

mySQL getting wrong columns that don't match up with other columns in same row

I am new to mySQL and I could use some help with the following query.
I have a table relating engine settings to an experiment number and engine rpms,
and also another table relating engine performance to experiment number and engine.
here is the query i am doing
SELECT performance.exp_no, performance.rpm, ignition_timing, horse_power
FROM engine_settings, performance
WHERE performance.rpm = engine_settings.rpm
ORDER BY rpm;
| exp_no | rpm | ignition_timing | horse_power |
| 2 | 1000 | 24.50 | 105.23 |
| 2 | 1000 | 24.00 | 105.23 |
| 1 | 1000 | 24.50 | 100.23 |
| 1 | 1000 | 24.00 | 100.23 |
| 1 | 2000 | 25.50 | 125.03 |
| 1 | 2000 | 25.00 | 125.03 |
| 2 | 2000 | 25.50 | 129.03 |
| 2 | 2000 | 25.00 | 129.03 |
| 1 | 3000 | 26.50 | 154.65 |
| 1 | 3000 | 26.00 | 154.65 |
| 2 | 3000 | 26.50 | 159.65 |
| 2 | 3000 | 26.00 | 159.65 |
| 1 | 4000 | 27.50 | 178.23 |
| 1 | 4000 | 27.00 | 178.23 |
| 2 | 4000 | 27.50 | 184.23 |
| 2 | 4000 | 27.00 | 184.23 |
| 2 | 5000 | 28.50 | 195.36 |
| 2 | 5000 | 28.00 | 195.36 |
| 1 | 5000 | 28.50 | 189.36 |
| 1 | 5000 | 28.00 | 189.36 |
20 rows in set (0.06 sec)
Now take the first two rows for example. Ignition_timing for experiment 2 is actually 24.00, and for experiment 1 it is 24.5. So why do i get both values for experiment 2?
Here are the results I would like to be getting . . .
| exp_no | rpm | ignition_timing | horse_power |
| 2 | 1000 | 24.00 | 105.23 |
| 1 | 1000 | 24.50 | 100.23 |
| 1 | 2000 | 25.50 | 125.03 |
| 2 | 2000 | 25.00 | 129.03 |
| 1 | 3000 | 26.50 | 154.65 |
| 2 | 3000 | 26.00 | 159.65 |
| 1 | 4000 | 27.50 | 178.23 |
| 2 | 4000 | 27.00 | 184.23 |
| 2 | 5000 | 28.00 | 195.36 |
| 1 | 5000 | 28.50 | 189.36 |
What is the correct query to get the above table? Thanks in advance!
Just a group by/ DISCTINCT needed
SELECT
performance.exp_no,
performance.rpm,
ignition_timing,
DISTINCT(horse_power)
FROM
engine_settings
inner join performance ON performance.rpm = engine_settings.rpm
ORDER BY rpm;
OR
SELECT
performance.exp_no,
performance.rpm,
ignition_timing,
horse_power
FROM
engine_settings
inner join performance ON performance.rpm = engine_settings.rpm
GROUP BY horse_power
ORDER BY rpm;
Your query is not joining on all required field. You are only joining on the rpm fields your query and it appears that the join is incomplete.
SELECT performance.exp_no, performance.rpm, ignition_timing, horse_power
FROM engine_settings, performance WHERE performance.rpm = engine_settings.rpm
ORDER BY rpm;
You should change your query to the following:
SELECT performance.exp_no, performance.rpm, ignition_timing, horse_power
FROM engine_settings INNER JOIN performance
ON engine_setting.rpm=performance.rpm
AND engine_Settings.exp_no = performance.exp_no
ORDER BY rpm;
As I dont have the table structures I might be wrong but I suspect that both rpm and exp_no is a primary key or foreign key somewhere.
Hope this helps. On a side note look at the join syntax in my example it is considered the new standard the way you are writting a join is a bit outdates but not wrong.