Sum the column while next value of rows is not null - mysql

I have a MySQL table called agent_log like picture 1. I want output like picture 2.
That means, wait_sec will be sum with next rows while a new uniqueid has come. When come a new uniqueid then again it will be sum with next wait_sec while next uniqueid are null.
Please see the attached images for clear the concept.
Picture 1/My Table
Picture 2/Expected output

Solution 1
select max(uniqueid), sum(wait_sec)
from (
select *, (select count(uniqueid) from agent_log a2 where a2.event_time < a1.event_time) gg
from agent_log a1
) as a
group by gg
Solution 2
select uniqueid, wait_total
from (
select a.*,
if(#prev_id is null, #wait_tot := #wait_tot + a.wait_sec, #wait_tot := a.wait_sec) AS wait_total,
#prev_id := a.uniqueid AS prev_id
from ( select #prev_id := NULL, #wait_tot := 0 ) i
join ( select * from agent_log order by event_time ) a
)a
where uniqueid is not null

Related

Select multiple tables in mysql

I need to make the following query:
I have 4 tables, the first is the main, in which with the 'id' is foreign in the other 3 tables. I need to get the date and description of each of the tables where it presents the id_tabla1. In some tables I have more records than in the other.
Is it possible to relate these tables?
Table 1 main
id_table1
Name
Table 2
id_table2
date
description
fk_table1
Table 3
id_table3
date
description
fk_table1
Table 4
id_table4
date
description
fk_table1
I want to get something like this:
This type of operation is a bit of a pain in MySQL. In fact, the result is not particularly "relational", because each column is a separate list. You can't do a join because there is no join key.
You can generate one in MySQL using variables and then use aggregation. Here is an example with two tables:
select id_table1,
max(t2_date) as t2_date,
max(t2_desc) as t2_desc,
max(t3_date) as t3_date,
max(t3_desc) as t3_desc
from ((select id_table1, NULL as t2_date, NULL as t2_desc, NULL as t3_date, NULL as t3_desc, 1 as rn
from table1 t1
) t1 union all
(select fk_table1, date as t2_date, description as t2_desc, NULL as t3_date, NULL as t3_desc,
(#rn1 := if(#fk1 = fk_table1, #rn1 + 1,
if(#fk1 := fk_table1, 1, 1)
)
) as rn
from table1 t1 cross join
(select #rn1 := 0, #fk1 := 0) params
order by fk_table1, date
) t1 union all
(select fk_table1, NULL, NULL, date as t3_date, description as t3_desc
(#rn2 := if(#fk2 = fk_table1, #rn2 + 1,
if(#fk2 := fk_table1, 1, 1)
)
) as rn
from table1 t1 cross join
(select #rn2 := 0, #fk2 := 0) params
order by fk_table1, date
)
) t
group by id_table1, rn;

Mysql query get SUM() specific row?

Is it possible to get specific row in query using like SUM?
Example:
id tickets
1 10 1-10 10=10
2 35 11-45 10+35=45
3 45 46-90 10+35+45=90
4 110 91-200 10+35+45+110=200
Total: 200 tickets(In SUM), I need to get row ID who have ticket with number like 23(Output would be ID: 2, because ID: 2 contains 11-45tickets in SUM)
You can do it by defining a local variable into your select query (in form clause), e.g.:
select id, #total := #total + tickets as seats
from test, (select #total := 0) t
Here is the SQL Fiddle.
You seem to want the row where "23" fits in. I think this does the trick:
select t.*
from (select t.*, (#total := #total + tickets) as running_total
from t cross join
(select #total := 0) params
order by id
) t
where 23 > running_total - tickets and 23 <= running_total;
SELECT
d.id
,d.tickets
,CONCAT(
TRIM(CAST(d.RunningTotal - d.tickets + 1 AS CHAR(10)))
,'-'
,TRIM(CAST(d.RunningTotal AS CHAR(10)))
) as TicketRange
,d.RunningTotal
FROM
(
SELECT
id
,tickets
,#total := #total + tickets as RunningTotal
FROM
test
CROSS JOIN (select #total := 0) var
ORDER BY
id
) d
This is similar to Darshan's answer but there are a few key differences:
You shouldn't use implicit join syntax, explicit join has more functionality in the long run and has been a standard for more than 20 years
ORDER BY will make a huge difference on your running total when calculated with a variable! if you change the order it will calculate differently so you need to consider how you want to do the running total, by date? by id? by??? and make sure you put it in the query.
finally I actually calculated the range as well.
And here is how you can do it without using variables:
SELECT
d.id
,d.tickets
,CONCAT(
TRIM(d.LowRange)
,'-'
,TRIM(
CAST(RunningTotal AS CHAR(10))
)
) as TicketRange
,d.RunningTotal
FROM
(
SELECT
t.id
,t.tickets
,CAST(COALESCE(SUM(t2.tickets),0) + 1 AS CHAR(10)) as LowRange
,t.tickets + COALESCE(SUM(t2.tickets),0) as RunningTotal
FROM
test t
LEFT JOIN test t2
ON t.id > t2. id
GROUP BY
t.id
,t.tickets
) d

Show in just one row all records that have the same id.

Lets say I have a table of product price history, which is the price and product id, with the following records:
id price
1 23
2 14
2 23
2 20
3 30
3 40
what I want is to show the data grouped by id, showing the prices at which has been sold each product.
What i expectis something like this:
id priceA PriceB PriceC
1 23 NULL NULL
2 14 23 20
3 30 40 NULL
This is not the right way to do things
you should use a separate table and try some primary keys.
suppose you have a poductprice table with id and price
make a view like
CREATE VIEW history AS (
SELECT
id,
CASE WHEN id = "1" THEN price END AS priceA,
CASE WHEN id = "2" THEN price END AS priceB,
CASE WHEN id = "3" THEN price END AS priceC
FROM productprice
);
SELECT * FROM history;
This requirement really a bad fit for SQL, but it can be achieved with a lot of fiddling involving "dynamic sql" and fudges to achieve te equivalent of row_number(). i.e. It would be easier to achieve with CTE and row_number() perhaps if MySQL gets bith this could be revisited.
Anyway, what is required is getting the prices into numbered columns, so the first price of each product goes in the first column, the second price in the second column and so on. So we need in the first instance a way to number the rows which will later be transformed into columns. In MySQL this can be done by using variables, like this:
select
#row_num := IF(#prev_value = p.id, #row_num+1, 1) AS RowNumber
, id
, price
, #prev_value := p.id
from (select distinct id, price from pricehistory) p
CROSS JOIN ( SELECT #row_num :=1, #prev_value :='' ) vars
order by id, price
So that snippet is used twice in the following. In the upper part it forms a set of case expressions that will do the transformation. I the lower part we combine those case expressions with the remainder of the wanted sql and then execute it.
set #sql = (
SELECT GROUP_CONCAT(col_ref)
FROM (
select distinct
concat(' max(case when RowNumber=',RowNumber,' then Price else NULL end) as c',RowNumber) col_ref
from (
select
#row_num := IF(#prev_value = p.id, #row_num+1, 1) AS RowNumber
, id
, price
, #prev_value := p.id
from (select distinct id, price from pricehistory) p
CROSS JOIN ( SELECT #row_num :=1, #prev_value :='' ) vars
order by id, price
) d
order by `RowNumber`
) dc
);
set #sql = concat('select id,', #sql,
' from (
select
#row_num := IF(#prev_value = p.id, #row_num+1, 1) AS RowNumber
, id
, price
, #prev_value := p.id
from (select distinct id, price from pricehistory) p
CROSS JOIN ( SELECT #row_num :=1, #prev_value :='''' ) vars
order by id, price
) d
Group By `id`');
#select #sql
PREPARE stmt FROM #sql;
EXECUTE stmt;
\\
The result of this, based on the sample given is:
id c1 c2 c3
1 1 23 NULL NULL
2 2 14 20 23
3 3 30 40 NULL
This solution can be tested and re-run at: http://rextester.com/AYAA36866
Note the fully generated sql reads like this:
select id
, max(case when RowNumber=1 then Price else NULL end) as c1
, max(case when RowNumber=2 then Price else NULL end) as c2
, max(case when RowNumber=3 then Price else NULL end) as c3
from (
select
#row_num := IF(#prev_value = p.id, #row_num+1, 1) AS RowNumber
, id
, price
, #prev_value := p.id
from (select distinct id, price from pricehistory) p
CROSS JOIN ( SELECT #row_num :=1, #prev_value :='' ) vars
order by id, price
) d
Group By `id`
You might want something like this:
SELECT id, GROUP_CONCAT(string SEPARATOR ' ') FROM priceHistory GROUP BY id;

Mysql difference between rows

i want to get price difference of car from 2 row through given following data.
i want to substract price column ex: (200-100),(300-200) and so on as data
My Table:
My desired output:
what i have tried
select t1.row_num1,t1.car_name
from
(
select (#row_num := #row_num +1) as row_num1 ,(select #row_num =0) r1, car_name,price
from car
)t1
I know that i don't have id column.hence i am generating row_number.
now i am getting problem to self join this table and get difference.
your help is appreciable.
Try This
set #next_row_price := null;
SELECT car_name , price, diff FROM(
SELECT car_name,price,(#next_row_price - price) * -1 AS diff,
IF(#next_row_price IS NULL, #next_row_price := price, 0) ,
IF(#next_row_price IS NOT NULL, #next_row_price := price, 0)
FROM car
) AS TEMP;
SQLFiddle
Although your output seems confusing nevertheless I am giving the following answer:
SOLUTION #1
SELECT
carsTable1.car_name,
carsTable1.price,
CASE WHEN ABS(carsTable1.price - (SELECT price FROM cars WHERE car_name='car 2')) = 0 THEN NULL ELSE
ABS(carsTable1.price - (SELECT price FROM cars WHERE car_name='car 2')) END diff
FROM
(SELECT
#rn := #rn + 1 row_number,
cars.car_name,
cars.price
FROM cars, (SELECT #rn := 0) var
) carsTable1;
Demo Here
Sample Input:
car_name price
car 1 100
car 2 200
car 3 300
Sample Output:
car_name price diff
car 1 100 100
car 2 200 NULL
car 3 300 100
Note: The price of car 2 is compared with the price of the rest of the cars. So the result shows null for car 2 since it's the reference car.
If I misunderstood your requirement then it must be : You want the price differences between the consecutive rows i.e. (No car,car1),(car1,car2), (car2,car3), (car3,car4)....
So in this case you can adopt the following query :
SOLUTION #2
SELECT
car_name,
cars.price,
CASE WHEN #currentPrice = 0 THEN NULL ELSE ABS(cars.price - #currentPrice) END AS diff,
#currentPrice := price
FROM cars ,(SELECT #currentPrice := 0) var
ORDER BY car_name
SQL FIDDLE BASED ON THIS QUERY
And if you want to omit the fourth column:
SELECT
t.car_name,
t.price,
t.diff
FROM
(
SELECT
car_name,
cars.price,
CASE WHEN #currentPrice = 0 THEN NULL ELSE (cars.price - #currentPrice) END AS diff,
#currentPrice := price
FROM cars ,(SELECT #currentPrice := 0) var
ORDER BY car_name ) t
SQL FIDDLE BASED ON THIS QUERY
Try this:-
CREATE TABLE #TempTable (rownum INT, price int, car_name VARCHAR(256));
INSERT INTO #TempTable (rownum, price, car_name)
SELECT
rownum = ROW_NUMBER() OVER (ORDER BY c.car_id),
c.price,
c.car_name
FROM car c;
SELECT
NEX.car_name + '-' + TT.car_name,
(nex.price - tt.price) AS Differences
FROM #TempTable TT
LEFT JOIN #TempTable prev ON prev.rownum = TT.rownum - 1
LEFT JOIN #TempTable nex ON nex.rownum = TT.rownum + 1;

my sql query to find sort two columns independently

there is a table having two columns say id and name , i want both columns to be sorted.
table :
id name
3 y
2 z
1 x
output should be
id name
1 x
2 y
3 z
can anybody do it in single sql query ???
You need need to do weird stuff. because what you want to do is weird.
select b1.id, b2.name from
(
select #row := #row +1 as row, id
from broken, (select #row := 0) rr
order by id asc
) b1
inner join
(
select #row2 := #row2 + 1 as row, name
from broken, (select #row2 := 0) rr
order by name asc
) b2
on b1.row = b2.row
demo fiddle: http://sqlfiddle.com/#!9/4d47c/7
Select *
, row_number() over (order by ID) as IDRow
, row_number() over (order by name) as NameRow
into #temp
from table
select a.ID, b.Name from #temp a
full outer join #temp b
on a.IDRow = b.NameRow
order by IDRow, NameRow
If you wanted, you could do this with subqueries instead of the temp table, but it'll probably be faster this way.