How to get next row value from Mysql Query - mysql

I want to get (select) the next row value from MySql query using SQLYog, with
the same id_voyage_order?
Example :
id_timesheet | id_voyage_order | Duration
----------------------------------------
1 | 106 | 0.00
2 | 106 | 24.00
3 | 210 | 12.00
4 | 106 | 12.00
5 | 210 | 24.00
i want to select it and make in View file Yii based on the same id_voyage order become like this and set the Duration of the last record become 0 :
id_timesheet | id_voyage_order | Duration
1. | 106 | 24.00
2. | 106 | 12.00
4. | 106 | 0.00

For instance:
SELECT a.id_timesheet
, a.id_voyage_order
, COALESCE(b.duration,0) duration
FROM my_table a
LEFT
JOIN
( SELECT x.*
, MAX(y.id_timesheet) previous
FROM my_table x
JOIN my_table y
ON y.id_voyage_order = x.id_voyage_order
AND y.id_timesheet < x.id_timesheet
GROUP
BY x.id_timesheet
) b
ON b.previous = a.id_timesheet
WHERE a.id_voyage_order = 106;

Related

Query to lookup reference tables on sum the result

I am new to SQL, would like to have your suggestions on how to solve this problem,
I have the sales information by type
I want to sum the Prices of certain references by Type and based on the resulting sum, fetch the values from another table and populate in the Output Column.
Group Type 100000 200000 300000
1 A 1 2 3
1 B 0 1 1
2 T 2 2 4
2 U 0 2 2
3 V 2 2 3
4 N 1 1 1
From the above table 2 we find the TYPE A and B belong to same group - Group 1. So in the first table, the query should sum Prices of the references belonging to the Group 1. If the sum is >100000 and <=200000 then based on the type the corresponding value must be chosen.
Incase the sum of Prices based on group is less than 100000 or the type not found in Table 2 then it should take the values from the below table
[+------+----+---+
| Type | 1 | 2 |
+------+----+---+
| A | 50 | 2 |
| B | 60 | 5 |
| C | 65 | 2 |
| D | 65 | 3 |
| E | 65 | 4 |
+------+----+---+][3]
Thus the final output for the above datasheet would be like below,
Order ID Reference Type Price Output
101 AAA A 500000 3
101 AAB B 100000 1
101 ABC C 20000 67
101 DCE B 50000 1
101 BOD D 200000 68
101 ZYZ E 200000 69
102 AAA A 20000 52
So for the first line, its TYPE A and Type A is present under Group 1 and in Group1 we also have Type 2. So for the same order ID 101 , the overall Sales of Type A and B is 650000 > 300000, therefore for Type A we chose the value 3 from the table 2. Since Type C is not present in Table 2, I went to Table 3 and added the two values and so on
Sorry for the long post. Hope my question is clear? Would like to have your expert opinion.
Thanks,
SS
Join all tables and make sure you do LEFT JOIN as we want to keep records from the first table even we don't have corresponding data in the second or third table.
For total count, give priority to the second table, use case when to verify in which range this mrp field is falling. If lies within a range pick count from the second table otherwise pick count from the third table.
SELECT
s.order_id,
s.reference,
s.`type`,
s.mrp,
#a:= IFNULL(g_total.Total, s.mrp) AS MRP_Total, -- #a variable to use it in CASE WHEN clause
CASE
WHEN #a > 100000 AND #a <= 200000 AND sg.`type` IS NOT NULL THEN sg.price_100000
WHEN #a > 200000 AND #a <= 300000 AND sg.`type` IS NOT NULL THEN sg.price_200000
WHEN #a > 300000 AND sg.`type` IS NOT NULL THEN sg.price_300000
ELSE tp.price_1 + tp.price_2
END Total
FROM sales s
LEFT JOIN sales_group sg ON s.`type` = sg.`type`
LEFT JOIN type_prices tp ON s.`type` = tp.`type`
LEFT JOIN (
SELECT
s.order_id, sgg.`group`, SUM(mrp) as Total
FROM sales s
INNER JOIN sales_group sgg ON s.`type` = sgg.`type`
GROUP BY s.order_id, sgg.`group`
) AS g_total -- Temp table to find total MRP, order and group wise
ON s.order_id = g_total.order_id AND sg.`group` = g_total.`group`
ORDER BY s.order_id, s.`type`;
Output:
sales
---
| order_id | reference | type | mrp | MRP_Total | Total |
---------------------------------------------------------
| 101 | AAA | A | 500000 | 650000 | 3 |
| 101 | DCE | B | 50000 | 650000 | 1 |
| 101 | AAB | B | 100000 | 650000 | 1 |
| 101 | ABC | C | 200000 | 200000 | 67 |
| 101 | BOD | D | 200000 | 200000 | 68 |
| 101 | ZYZ | E | 200000 | 200000 | 69 |
| 102 | AAA | A | 20000 | 20000 | 52 |
Note: sg.type IS NOT NULL is added in CASE WHEN clause because if we don't have any mapping in the second table, we should move to ELSE part which refers to the third table.

Latest datetime from unique mysql index

I have a table. It has a pk of id and an index of [service, check, datetime].
id service check datetime score
---|-------|-------|----------|-----
1 | 1 | 4 |4/03/2009 | 399
2 | 2 | 4 |4/03/2009 | 522
3 | 1 | 5 |4/03/2009 | 244
4 | 2 | 5 |4/03/2009 | 555
5 | 1 | 4 |4/04/2009 | 111
6 | 2 | 4 |4/04/2009 | 322
7 | 1 | 5 |4/05/2009 | 455
8 | 2 | 5 |4/05/2009 | 675
Given a service 2 I need to select the rows for each unique check where it has the max date. So my result would look like this table.
id service check datetime score
---|-------|-------|----------|-----
6 | 2 | 4 |4/04/2009 | 322
8 | 2 | 5 |4/05/2009 | 675
Is there a short query for this? The best I have is this, but it returns too many checks. I just need the unique checks at it's latest datetime.
SELECT * FROM table where service=?;
First you need find out the biggest date for each check
SELECT `check`, MAX(`datetime`)
FROM YourTable
WHERE `service` = 2
GROUP BY `check`
Then join back to get the rest of the data.
SELECT Y.*
FROM YourTable Y
JOIN ( SELECT `check`, MAX(`datetime`) as m_date
FROM YourTable
WHERE `service` = 2
GROUP BY check) as `filter`
ON Y.`service` = `filter`.service
AND Y.`datetime` = `fiter`.m_date
WHERE Y.`service` = 2

MySql selecting greatest difference between 2 rows within the past day

I have a table that sort of looks like this
id | name | c1 | c2 | c3 | c4 | time
-------------------------------------------------
1 | miley | 23 | 11 | 21 | 18 | 2013-01-13 20:26:25
2 | john | 31 | 29 | 23 | 27 | 2013-01-14 20:26:25
3 | steve | 44 | 31 | 33 | 35 | 2013-01-14 20:26:25
4 | miley | 34 | 44 | 47 | 48 | 2013-01-15 08:26:25
5 | john | 27 | 53 | 49 | 52 | 2013-01-15 08:26:25
6 | steve | 27 | 62 | 50 | 64 | 2013-01-16 08:26:25
7 | miley | 44 | 54 | 57 | 87 | 2013-01-16 20:26:25
8 | john | 37 | 93 | 59 | 62 | 2013-01-17 20:26:25
9 | steve | 85 | 71 | 87 | 74 | 2013-01-17 20:26:25
...etc
*note: this is a random table I made up to just give you an idea of what my table looks like
I need to grab the name for who had the greatest change in a specific column over the course of a specific date range. I've tried a bunch of different queries by can't get one to work. I think my closest solution is something like...
SELECT table1.name, MAX(table1.c1-h.c1) as maxDiff
FROM table_a as table1
LEFT JOIN table_a as table2
ON table2.name=table1.name AND table1.c1>table2.c1
WHERE table2.c1 IS NOT NULL
What am I doing wrong? To be clear, I want to be able to select a range of dates then determine who has the biggest difference for that date range in a determined column. Also note that the data only increments over time, so the first capture of any day will always be <= the last capture of the day for that person.
It sounds like you will be needing a nested query. First, a query of each person on their own measurements within the date range, then order it by the biggest and take the top 1... something like this may work for you...
select
PreGroupByName.`Name`,
PreGroupByName.MaxC1 - PreGroupByName.MinC1 as MaxSpread
from
( select
t1.`Name`,
min( t1.c1 ) as MinC1,
max( t1.c1 ) as MaxC1
from
table_a t1
where
t1.`time` between '2013-01-01' and '2013-01-17' -- or whatever date/time range
group by
t1.`Name` ) as PreGroupByName
order by
MaxSpread DESC
limit 1
SELECT
`id`,`name`
,MAX(`c1`)-MIN(`c1`) AS `diff_c1`
-- ,MAX(`c2`)-MIN(`c2`) AS `diff_c2`
-- ,MAX(`c3`)-MIN(`c3`) AS `diff_c3`
-- ,MAX(`c4`)-MIN(`c4`) AS `diff_c4`
FROM `the_table`
WHERE `time` BETWEEN '2013-01-13 20:26:25' AND '2013-01-17 20:26:25'
GROUP BY `name`
ORDER BY `diff_c1` DESC -- whichever you want to evaluate
LIMIT 1

MYSQL - Selecting data from second row in a large table

I have an external 3rd party program export the database to mysql in real time, and I want to show data for reporting. So, I can't change the structure, because it's being sync in real time.
The table structure is something like this
ID | Date | Transaction
-----------------------------
12 | 2012-11-01 | 200
12 | 2012-11-02 | 250
12 | 2012-11-03 | 150
12 | 2012-11-04 | 1000
12 | 2012-11-05 | 225
....
13 | 2012-11-01 | 175
13 | 2012-11-02 | 20
13 | 2012-11-03 | 50
13 | 2012-11-04 | 100
13 | 2012-11-05 | 180
13 | 2012-11-06 | 195
The data are very large and keep getting bigger each day.
What I want to do is to build a report (view table) based on something like this:
ID | Date | Transaction | Prev Day Transaction
----------------------------------------------------
12 | 2012-11-01 | 200 | 0
12 | 2012-11-02 | 250 | 200
12 | 2012-11-03 | 150 | 250
12 | 2012-11-04 | 1000 | 150
12 | 2012-11-05 | 225 | 1000
....
13 | 2012-11-01 | 175 | 0
13 | 2012-11-02 | 20 | 175
13 | 2012-11-03 | 50 | 20
13 | 2012-11-04 | 100 | 50
13 | 2012-11-05 | 180 | 100
13 | 2012-11-06 | 195 | 180
I just can't get the fast select statement. Currently the original data is already 283,120 rows. And it will grow like 500 rows daily.
I've tried something like:
SELECT *, (SELECT transaction FROM table as t2 WHERE t1.id=t2.id
AND t1.date>t2.date ORDER BY t2.date DESC LIMIT 0,1)
FROM table AS t1
It's working, but the select statement is very slow. Most of the time, it's getting cut of in the middle of the operation.
What I need help is a very fast sql statement, which later on I could use to build the view table.
See this link: http://sqlfiddle.com/#!2/54a5e/12
select t.id,t.cDate,t.cTrans
,(case when #pID=t.id then #pTran else 0 end) as preT
,(#pID :=t.id) as `tID`,(#pTran := t.cTrans) as `tTrans`
from tb_test_1 as t,(select #pID = 0, #pTran = 0) as t2
order by id,cDate;
tID and tTrans column must be retained, and cannot display on page.
Please forgive me as I only know a little english!
Try this query -
SELECT t1.*, COALESCE(t2.transaction, 0) Prev_Day_Transaction FROM trans t1
LEFT JOIN (SELECT * FROM trans ORDER BY id, date DESC) t2
ON t1.id = t2.id AND t1.date > t2.date
GROUP BY t1.id, t1.date;
+------+------------+-------------+----------------------+
| id | date | transaction | Prev_Day_Transaction |
+------+------------+-------------+----------------------+
| 12 | 2012-11-01 | 200 | 0 |
| 12 | 2012-11-02 | 250 | 200 |
| 12 | 2012-11-03 | 150 | 250 |
| 12 | 2012-11-04 | 1000 | 150 |
| 12 | 2012-11-05 | 225 | 1000 |
| 13 | 2012-11-01 | 175 | 0 |
| 13 | 2012-11-02 | 20 | 175 |
| 13 | 2012-11-03 | 50 | 20 |
| 13 | 2012-11-04 | 100 | 50 |
| 13 | 2012-11-05 | 180 | 100 |
| 13 | 2012-11-06 | 195 | 180 |
+------+------------+-------------+----------------------+
Add composite index (id, date) to the table.
===========================
ALTER TABLE mt4_daily
ADD INDEX IX_mt4_daily_DATE (DATE);
ALTER TABLE mt4_daily
ADD INDEX IX_mt4_daily (ID, DATE);
Divide the table into few pars through select statements and join them using UNION Set operator. As all set operators are parallel operation you will get the data very quickly. You can divide the data by using the Unique numeric column in your table. e.g.
select * from tbl_x where col1%3=0 union
select * from tbl_x where col1%3=1 union
select * from tbl_x where col1%3=2 ...
The above sql query divides the data and fetches in parallel way
I would try to write the query like this:
SELECT
tbl.ID,
tbl.Date,
tbl.Transaction,
COALESCE(tbl1.Transaction,0) as PrevDay
FROM
tbl left join tbl tbl1
on tbl.ID = tbl1.ID
and tbl.Date = tbl1.Date + INTERVAL 1 DAY
(this will work only if you make sure that the table contains all days, if you miss one day, the next day will always show PrevDay as 0, i am not sure if this is what you need).
EDIT: i would try this solution that works even if some days are missing:
SELECT
tbl.id,
tbl.date,
tbl.Transaction,
COALESCE(tbl1.Transaction,0) as PrevDay
FROM
(SELECT tbl.id, tbl.date as d1, max(tbl1.ddate) as d2
FROM tbl LEFT JOIN tbl tbl1
ON tbl.id = tbl1.id and tbl.date>tbl1.date
GROUP BY tbl.id, tbl.date) t
LEFT JOIN tbl on tbl.id = t.id and DATE(tbl.ddate) = DATE(t.d1)
LEFT JOIN tbl tbl1 ON tbl1.id = t.id and DATE(tbl1.date) = DATE(t.d2)

SQL query with calculated dynamic min max

I got an sql issue. I have two tables which look like this:
first TABLE X second TABLE Y
TabX_ID| DATE | Value Z TabY_ID|TabX_ID | DATE | Value X | Value Y
4711 | 15.01 | 12 1 | 4711 | 15.01| 123 | 876
4711 | 20.01 | 5 2 | 4711 | 16.01| 12 | 54
4711 | 25.01 | 67 3 | 4711 | 17.01| 23 | 38
4 | 4711 | 20.01| 56 | 13
5 | 4711 | 23.01| 1 | 5
I need to assing all the data from TABLE Y to the data in the TABLE X DATE to the fitting
timeframe.
I cant use a simple min - max because it changes.
1. DATE min 15.01 DATE-max:19.01
2. DATE-min:20.01 DATE-max:24.01
3. DATE-min:25.01 DATE-max:...
So it looks like this
1 | 15.01 | 123 | 876
4711 | 15.01 | 12 -> 2 | 16.01 | 12 | 54
3 | 17.01 | 23 | 38
4711 | 20.01 | 5 -> 4 | 20.01 | 56 | 13
5 | 23.01 | 1 | 5
First I need to perform calculations with the TABLE Y VALUES X an Y and after that I need the VALUE Z
from TABLE X. So it looks like this:
ID | DATE | Calculated_Val
4711| 15.01 | 345
4711| 20.01 | 892
Is there a way to do this?
thx in advance
Not sure about MySQL but if you are doing this with Oracle, I would use the LEAD analytic function to get the next date value in the future in tableX and then join that to tableY.
An example of this would be:
select
tabX_id,
date_val as min_date,
next_date_val as max_date,
valueZ,
valueX,
valueY,
y.date_val as tabY_date
from (
select
tabX_id,
date_val,
lead(date_val) over (partition by tabx_id order by date_val)
as next_date_val,
valueZ
from tabX
) x
join tabY y on (x.tabX_id = y.tabX_id and
y.date_val >= x.date_val and
(x._next_date_val is null or y.date_val < x.next_date_val))
Note that I haven't modified the next value of the date so am using a less-than condition. This is probably appropriate if you have a time component in any of the date fields but might not be exactly what you want if they are just date value.
This is a simple join and group by:
select x.TabX_ID, y.DATE, min(ValueX), min(ValueY)
from TableX x
join TableY y
on x.TabX_ID = y.TabX_ID
and x.DATE = y.DATE
group by x.TabX_ID, y.DATE