I have a value store in a database like this:
ID | Date | Value
----------------------------------------------
1 | 11/20 | 1
1 | 11/21 | 2
2 | 11/20 | 10
2 | 11/21 | 20
However, I need it to be like this:
Date | Value ID 1 | Value ID 2
----------------------------------------------
11/20| 1 | 10
11/21| 2 | 20
So the new column can be plot in a trend (column 1 = date, column 2 = value#1, column 3 = value #2, column 4 = value#4, etc).
Here is the query for a single tag:
SELECT *
FROM (
SELECT ID, _date, ESYNC_TAGSHISTORY.Val, #curRow := #curRow + 1 AS row_number
FROM ESYNC_TAGSHISTORY
JOIN (SELECT #curRow:=0) i
INNER JOIN ESYNC_TAGS ON ESYNC_TAGSHISTORY.TAGID=ESYNC_TAGS.ID
WHERE ESYNC_TAGS.NAME='I_TT_21052' AND ESYNC_TAGS.STATIONID=1 AND (_date BETWEEN now()-INTERVAL 45 MINUTE AND now()) ) s
WHERE row_number mod 60 = 0;
And the results:
ID | Date | Value ID 1 | Row
----------------------------------------------
1 | 11/20| 1 | 1
1 | 11/21| 2 | 2
EDIT :
With some modification my query look like this
SELECT *
FROM (
SELECT ID, _date, ESYNC_TAGSHISTORY.Val, #curRow := #curRow + 1 AS row_number,
if (ESYNC_TAGS.NAME='I_TT_21052', ESYNC_TAGSHISTORY.Val, NULL) as 'I_TT_21052',
if (ESYNC_TAGS.NAME='I_TT_91214', ESYNC_TAGSHISTORY.Val, NULL) as 'I_TT_40011'
FROM ESYNC_TAGSHISTORY
JOIN (SELECT #curRow:=0) i
INNER JOIN ESYNC_TAGS ON ESYNC_TAGSHISTORY.TAGID=ESYNC_TAGS.ID
WHERE ESYNC_TAGS.STATIONID=1 AND (_date BETWEEN now()-INTERVAL 5 MINUTE AND now()) ) s
WHERE row_number mod 1 = 0
ORDER BY ID ,_date;
Result look like this
SQL RESULT
My Problem now is to move the data from the last column at the same place as the other (get the value line up with the date)
EDIT #2 : Finally for further reference query look like this :
SELECT _date, I_TT_21052, I_TT_40011, row_number
From(
SELECT max(_date) as _date, max(I_TT_21052) as I_TT_21052, max(I_TT_40011) as I_TT_40011, #curRow := #curRow + 1 AS row_number
FROM (
SELECT ID, _date, ESYNC_TAGSHISTORY.Val,
if (ESYNC_TAGS.NAME='I_TT_21052', ESYNC_TAGSHISTORY.Val, NULL) as 'I_TT_21052',
if (ESYNC_TAGS.NAME='I_TT_91214', ESYNC_TAGSHISTORY.Val, NULL) as 'I_TT_40011'
FROM ESYNC_TAGSHISTORY
JOIN (SELECT #curRow:=0) i
INNER JOIN ESYNC_TAGS ON ESYNC_TAGSHISTORY.TAGID=ESYNC_TAGS.ID
WHERE ESYNC_TAGS.STATIONID=1 AND (_date BETWEEN now()-INTERVAL 24 HOUR AND now()) ) s
GROUP BY _date)v
WHERE row_number mod 150 = 0;
select
case when id=1 then count(Id) else 0 end) as Value1,
case when id=2 then count(Id) else 0 end) as Value2
from ESYNC_TAGSHISTORY
This is not exact but try this kind of query you will get result
Related
having a table structure of id and a name:
create table Mytable (
id integer not null,
name varchar(30) not null,
unique(id)
);
insert into Mytable (id,name) values
(1 , 'one'),
(2 , 'two'),
(3 , 'three'),
(4 , 'four'),
(6 , 'six');
How may I get a mix of even and odd rows in a result table like:
even | odd
-----------
null one '0 is not in Mytable so it puts null value
two three
four null '5 and 6 are not in Mytable so it puts null value
six null
I was trying to first get the following as a template and use it later as
a dictionary:
SELECT MIN(id-1) as id,MAX(id-1) as col
FROM Mytable
GROUP BY FLOOR((id+1)/2);
I get:
id col
0 1
2 3
5 5
But I do not know how to continue
For MySQL Version <= 5.7, You can use the below query
Query 1:
SELECT
MAX(CASE WHEN m.id % 2 = 0 THEN name END) AS even,
MAX(CASE WHEN m.id % 2 = 1 THEN name END) AS odd
FROM
(
SELECT
(SELECT MAX(id) FROM mytable) AS maxid,
#rn := #rn + 1 AS rn,
(SELECT IF((#rn * 2) <= maxid, #rn, NULL)) AS rid
FROM
mytable
JOIN
(SELECT #rn := -1) AS var
) AS t
JOIN
mytable m ON FLOOR(m.id/2) = t.rid
GROUP BY rid;
Result 1:
even | odd
:--- | :----
null | one
two | three
four | null
six | null
Demo 1:
db fiddle
Query 2:
After confirmation based on #Madhur Bhaiya comment. If there is no row for id = 8 and 9 then it will show null, null.
SELECT
MAX(CASE WHEN m.id % 2 = 0 THEN name END) AS even,
MAX(CASE WHEN m.id % 2 = 1 THEN name END) AS odd
FROM
(
SELECT
(SELECT MAX(id) FROM mytable) AS maxid,
#rn := #rn + 1 AS rn,
(SELECT IF((#rn * 2) <= maxid, #rn, NULL)) AS rid
FROM
(SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) t
JOIN
(SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) t2
JOIN
(SELECT #rn := -1) var -- currently it will return 1..100, if needed more add joins based on your needs
) AS t
LEFT JOIN
mytable m ON FLOOR(m.id/2) = t.rid
GROUP BY rid HAVING rid IS NOT NULL;
Result 2:
even | odd
:------ | :-----
null | one
two | three
four | null
six | null
null | null
null | eleven
null | null
null | null
sixteen | null
Demo 2:
db fiddle
For MySQL Version > 8.0, You can use #Nick query but if you need null, null like Result 2 mentioned for <= v5.7 then add LEFT JOIN with ORDER BY clause.
Query:
with recursive maxid as (
select max(id) as id from Mytable)
, cte as (
select 0 as rid
union all
select rid + 1
from cte
cross join maxid
where (rid + 1) * 2 <= maxid.id)
select max(case when m.id % 2 = 0 then name end) as even,
max(case when m.id % 2 = 1 then name end) as odd
from cte
left join Mytable m on floor(m.id / 2) = cte.rid
group by rid order by rid;
Result:
even | odd
:------ | :-----
null | one
two | three
four | null
six | null
null | null
null | eleven
null | null
null | null
sixteen | null
Demo: db fiddle
Credits: Thanks to #Nick, #Madhur Bhaiya for the fiddle and the logic used to create this query.
Here's a CTE based query that will work in SQL Server and MySQL > v8.0 (with the addition of the keyword recursive before maxid). It generates a list of rows that encompasses the pairs of MyTable values (in the sample, this is 0,1,2,3) and then JOINs that to Mytable to extract the even/odd column values:
with maxid as (
select max(id) as id from Mytable)
, cte as (
select 0 as rid
union all
select rid + 1
from cte
cross join maxid
where (rid + 1) * 2 <= maxid.id)
select max(case when m.id % 2 = 0 then name end) as even,
max(case when m.id % 2 = 1 then name end) as odd
from cte
join Mytable m on m.id / 2 = cte.rid
group by rid
Output:
even odd
one
two three
four
six
Demo on dbfiddle
I am trying to update position for my player in present in table.
This table consists of name , id, points and position.
Default value of points is 0 then position will be Unranked.
If two users have same points then there positions will be same.
Demo table
id | name | points | position
1 | a | 0 | Unranked
2 | b | 120 | 2
3 | c | 130 | 3
4 | d | 120 | 1
Required result should be
id | name | points | position
1 | a | 0 | Unranked
2 | b | 120 | 2
3 | c | 130 | 1
4 | d | 120 | 2
Query will be like for unranked update mytable set position = 'Unranked' Where points = 0
How will i use points and position set query ?
There's no need to hold the computed column position in the table. The following works for all versions :
create table tab ( id int, name varchar(1), points int );
insert into tab values
(1,'a', 0),
(2,'b',120),
(3,'c',130),
(4,'d',120);
select t.id, t.name, t.points,
( case when points = 0 then 'Unranked' else t.rnk end ) as position
from
(
select t1.*,
#rnk := if(#pnt = points,#rnk,#rnk + 1) rnk,
#pnt := points
from tab t1
cross join (select #rnk := 0, #pnt := 0 ) t2
order by points desc
) t
order by t.id;
id name points position
-- ---- ------ --------
1 a 0 Unranked
2 b 120 2
3 c 130 1
4 d 120 2
If you want to hold the column position in your table, then you can use the following update statement by binding through primary column id :
update tab tt
set position = ( select
( case when points = 0 then 'Unranked' else t.rnk end ) as position
from
(
select t1.*,
#rnk := if(#pnt = points,#rnk,#rnk + 1) rnk,
#pnt := points
from tab t1
cross join (select #rnk := 0, #pnt := 0 ) t2
order by points desc
) t
where t.id = tt.id );
Rextester Demo
This is a pain. You can get the results you want with a subquery, but that doesn't quite work in an update clause. In a select, you can do:
select t.*,
(select 1 + count(*)
from t t2
where t2.points > 0 and t2.points > t.points
) as rank
from t;
You can now incorporate this into an update:
update t join
(select t.*,
(select 1 + count(*)
from t t2
where t2.points > 0 and t2.points > t.points
) as new_position
from t;
) tt
on t.id = tt.id
set t.position = tt.new_position
where t.points > 0;
If your version of MySQl (MySQL 8.x) supports window function then following is possible:
SELECT name,
RANK() OVER (
ORDER BY points DESC
) position
FROM mytable
where points != 0
Selected data can be then joined for the update like in the answer from Gordon Linoff.
I have a table for my users scores like this:
id | kills
----------
2 | 1
1 | 1
1 | 5
1 | 3
2 | 4
2 | 5
3 | 5
I want to get the first 2 rows of each player which have more than 2 kills. So the result should look like this
id | kills
----------
1 | 5
1 | 3
2 | 4
2 | 5
3 | 5
I tried this but it doesn't work:
SELECT *
FROM user_stats us
WHERE
(
SELECT COUNT(*)
FROM user_stats f
WHERE f.id=us.id AND f.kills > 2
) <= 2;
I suspect that you just want the two largest values for users that have kills > 2. If so, use variables:
select us.*
from (select us.*,
(#rn := if(#i = id, #rn + 1,
if(#i := id, 1, 1)
)
) as seqnum
from user_stats us cross join
(select #rn := 0, #i := -1) params
where us.kills > 2
order by us.id, kills desc
) us
where seqnum <= 2;
select * from user_stats
where (id,kills) in (select id, max(kills) from user_stats where kills > 2 group by id
union
select id, min(kills) from user_stats where kills > 2 group by id)
Try this. I am coming from Oracle, where rownum is a count of rows selected. This should have the same effect.
select #rownum:=#rownum+1, us.*
from user_stats us , (select #rownum := 0) r
where id in (
select id from user_stats f
group by id
having count(*) > 2
)
and #rownum < 3;
based on response of vkp. Take min and max when id has more then 1 kill
select id, max(kills)
from user_stats
group by id
having count(kills) > 2
union
select id, min(kills)
from user_stats
group by id
having count(kills) > 2
order by id
Here's my table structure:
+-------+--------+----------+
| item | price | quantity |
+-------+--------+----------+
| 22452 | 579150 | 4 |
| 34664 | 334425 | 7 |
| 32249 | 204750 | 3 |
| 39970 | 97500 | 5 |
| 36907 | 116415 | 6 |
| 4338 | 207451 | 17 |
| 23425 | 388050 | 4 |
| 23427 | 532350 | 14 |
| 76080 | 180000 | 6 |
| 76076 | 400000 | 4 |
+-------+--------+----------+
Item is not unique and there could be anywhere from 1 to a few thousand rows for each item, so I'm grouping by item for the results. My current query is the following:
SELECT item AS id,
COUNT(item) as total,
ROUND(AVG(price/quantity)) AS mean,
ROUND(MIN(price/quantity)) AS cheapest
FROM `data`
GROUP BY item;
In addition to these 4 results, I would like to calculate the average price of the bottom 15% of rows of the (price/quantity) value (not < 0.15*MAX(price/quantity) but 0.15*total, ordered by (price/quantity) ASC). The solution I thought of involved temporary tables using the count of that item as the limiter, but I'd highly prefer it to be a single query if possible. I'm sure I'll need a subquery in here, but I'm unsure of how to go about getting the count for that particular item and then limiting by 15% of that result.
UPDATE WITH ANSWER FROM BELOW
Using #GordonLinoff answer below got me basically all the way there. I did run into two issues, however. The biggest one was the #rn variable wasn't resetting, which was causing it to keep increment and subsequently only the first row of the items was getting included. The second was any item where 15% of the number of times it appears in the table is < 1, NULL was being returned. The corrections were minor and I've included the final query I used below:
SELECT item AS id,
COUNT(item) as total,
ROUND(AVG(price/quantity)) AS mean,
ROUND(MIN(price/quantity)) AS cheapest,
ROUND(avg(case when rn <= IF(cnt * 0.15 < 1, cnt, cnt * 0.15) then price/quantity end)) as Cheapest15Percent
FROM
(SELECT d.*, cnt, IF(#item = d.item, #rn := #rn + 1, if(#item := d.item, #rn := 1, 1)) as rn
FROM `data` d LEFT JOIN
(SELECT item, COUNT(*) cnt FROM `udata` GROUP BY item) di
ON d.item = di.item CROSS JOIN
(SELECT #rn := 0, #item := -1) vars
ORDER BY d.item, d.price/d.quantity) d
GROUP BY d.item;
This assumes that you want the average of the cheapest 15% for each item.
The following query enumerates the rows for each item and gets the total rows:
select d.*, cnt,
if(#item = item, #rn := #rn + 1, if(#item := item, 1, 1)) as rn
from `data` d left join
(select item, count(*) cnt
from data
group by item
) di
on d.item = di.item cross join
(select #rn := 0, #item := -1) vars
order by item, price/quantity;
You can then basically plug this into your query and do conditional aggregation:
SELECT item AS id,
COUNT(item) as total,
ROUND(AVG(price/quantity)) AS mean,
ROUND(MIN(price/quantity)) AS cheapest,
avg(case when rn <= cnt * 0.15 then price/quantity end) as Cheapest15Percent
FROM (select d.*, cnt,
if(#item = item, #rn := #rn + 1, if(#item := item, 1, 1)) as rn
from `data` d left join
(select item, count(*) cnt
from data
group by item
) di
on d.item = di.item cross join
(select #rn := 0, #item := -1) vars
order by item, price/quantity
) d
GROUP BY item;
I've got a table of data thats ordered by a non-primary key e.g.
id | likes
4 | 6
2 | 5
5 | 2
3 | 2
1 | 2
I need a query to find the row after id #5 which would be id #3.
I've tried using row numbers and written this but it seems really inefficient
select * from (
SELECT l.id,
l.likes,
#curRow := #curRow + 1 AS row_number
FROM sk_posters l
JOIN (SELECT #curRow := 0) r
WHERE active = 'yes'
order by likes desc, id desc)
as mycount where row_number =
(select row_number from (
SELECT l.id,
l.likes,
#curRow := #curRow + 1 AS row_number
FROM sk_posters l
JOIN (SELECT #curRow := 0) r
WHERE active = 'yes'
order by likes desc, id desc)
as mycount
where id=5)+1 limit 1
If there a better, more efficient way to do this?
You can use limit at the end of query like
SELECT * FROM YOUR_TABLE LIMIT 2,1