Mysql update max value with group by - mysql

I have a simple table that has many rows already:
id grade ...
1 1 ...
2 2 ...
3 2 ...
4 1 ...
5 1 ...
Now i want to add a column "relative_order", which is the order in that grade. So the table becomes:
id grade ... relative_order
1 1 ... 1
2 2 ... 1
3 2 ... 2
4 1 ... 2
5 1 ... 3
After i add the column, all the relative_order becomes 0 first. How can i fill the relative_order column using update syntax?
I tried using inner join, but failed:
UPDATE table AS i
INNER JOIN(
SELECT max(relative_order) as mOrder,grade
FROM table
GROUP BY grade
) AS j
ON i.grade = j.grade
SET i.relative_order = j.mOrder + 1

You could use this SELECT query that will return the relative_order that you need:
SELECT
t1.id,
t1.grade,
COUNT(t2.id) relative_order
FROM
yourtable t1 INNER JOIN yourtable t2
ON t1.grade=t2.grade AND t1.id>=t2.id
GROUP BY
t1.id,
t1.grade
or if you want to update the value, you can join your table with the previous query, like this:
UPDATE
yourtable INNER JOIN (
SELECT
t1.id,
t1.grade,
COUNT(t2.id) relative_order
FROM
yourtable t1 INNER JOIN yourtable t2
ON t1.grade=t2.grade AND t1.id>=t2.id
GROUP BY
t1.id,
t1.grade) seq
ON yourtable.id=seq.id AND yourtable.grade=seq.grade
SET
yourtable.relative_order = seq.relative_order
Please see fiddle here.

Related

how to exclude first and last row if group it on particular id

I have sample table with data like this
id uniqueid values
1 6 0
2 6 1
3 6 2
4 6 0
5 6 1
I want result like this
id uniqueid values
2 6 1
3 6 2
4 6 0
I tried like this
select id,uniqueid,values
FROM t1
WHERE
id not in(SELECT concat(MAX(message_id_pk),',',min(message_id_pk)) FROM t1
where uniqueid=6)
and `uniqueid`=6
GROUP BY uniqueid
but its not working
You can achieve the desired results by doing self join, Inner query will get the the max and min ids for per group and outer query will filter out the results by using minid and maxid
select a.*
from demo a
join (
select `uniqueid`,min(id) minid, max(id) maxid
from demo
where uniqueid=6
group by `uniqueid`
) b using(`uniqueid`)
where a.id > b.minid and a.id < b.maxid /* a.id <> b.minid and a.id <> b.maxid */
Demo
Also you can do it by using 2 sub-queries with EXISTS to exclude the min and max id of each uniqueid.
Query
select `id`, `uniqueid`, `values`
from `your_table_name` t1
where exists (
select 1 from `your_table_name` t2
where t2.`uniqueid` = t1.`uniqueid`
and t2.`id` > t1.`id`
)
and exists(
select 1 from `your_table_name` t2
where t2.`uniqueid` = t1.`uniqueid`
and t2.`id` < t1.`id`
);
Here is a sql fiddle demo
Try this -
SELECT id, uniqueid, values
FROM YOUR_TABLE
WHERE id NOT IN (MIN(id), MAX(id));

How can i avoid duplication while joining two tables

i have two tables
1. test 1
2. test 2
First table has
**id** - **name**
1 - kerala
2 - Tamilnadu
Second table
**name** - **jid**
value 1 - 1
value 2 - 1
value 3 - 1
value 4 - 1
value 5 - 2
My Query --
SELECT t1.name, t2.name
FROM test1 t1
INNER JOIN test2 t2
WHERE t1.id = t2.jid
now i get this result
**name** - **name**
Kerala - value 1
kerala - value 2
kerala - value 3
kerala - value 4
But i need a result like this
Kerala - value 1
- value 2
- value 3
- value 4
the value ' Kerala ' should not be repeated .
you can user Group concat method.Pls check below query
SELECT t1.name,GROUP_CONCAT(t2.name) FROM test1 t1 INNER JOIN test2 t2 WHERE t1.id = t2.jid
You can use the following query:
SELECT CASE
WHEN t2.name = t3.firstName THEN t1.name
ELSE ''
END AS name,
t2.name
FROM test1 t1
INNER JOIN test2 t2 ON t1.id = t2.jid
INNER JOIN (
SELECT jid, MIN(name) AS firstName
FROM test2
GROUP BY jid) AS t3 ON t2.jid = t3.jid
This will produce the required result as long as there is a single record having MIN(name) per jid in test2 table.
Demo here
try this
SELECT IF (#oldname = name1,'',name1),
name2,
#oldname:=name1 AS oldname FROM
(
SELECT t1.name AS name1, t2.name AS name2
FROM test1 t1
INNER JOIN test2 t2
WHERE t1.id = t2.jid
) t,
(SELECT #oldname:='' ) tmp;
I don't think it's possible - you can't have empty values inside returned values.

Joining two tables on interval basis

In SQL, suppose that I have table A
ID
--
1
3
5
and table B
ID2
---
1
2
3
4
5
6
To get the result similar to:
ID | ID2
----------
1 | 1
1 | 2
3 | 3
3 | 4
5 | 5
5 | 6
For an explanation, an element in column ID2 will be mapped to the highest value in the column ID that is less than or equal to the said element in ID2.
For example, 4 in column ID2 is mapped to 3 from column ID, because 3 is the largest value in column ID which is less than or equal to 4.
Is it possible at all to do this in sql?
What I would do is start by joining the two tables on the condition that the id in the first table is less than or equal to that in the second table, like this:
SELECT t1.id, t2.id AS id2
FROM t1
JOIN t2 ON t2.id >= t1.id;
Once you have that, you can select the maximum id from the first table, and group by the id from the second table to get the largest pairs:
SELECT MAX(t1.id) AS id, t2.id AS id2
FROM t1
JOIN t2 ON t2.id >= t1.id
GROUP BY t2.id;
SQL Fiddle seems to be down but I will update with a link as soon as I can.
SELECT MAX(A.ID) ID, B.ID2
FROM A
INNER JOIN B ON B.ID2 >= A.ID
GROUP BY B.ID2
If you only need the matching ID column:
select b.*,
(select max(ID) from a where a.ID <= b.ID2) as a_Id
from b
If you need more columns:
select *
from a
join
(
select b.*,
(select max(ID) from a where a.ID <= b.ID2) as a_Id
from b
) as b
on a.Id = b.a_Id

Mysql left join fails to returns all values from first table

I've two tables named table1 and table2. table2 may have elements from table1. I'd like to show all the results from table2 with the price if available in table1 and with status 1. If no product matches in table1 and also status is 0, need to return price as 0.
table1
id pname item_code price status
1 product1 abcd 200 1
2 product2 pqrs 500 1
3 product3 wxyz 425 1
4 product5 mnop 100 0
and table2 as follows
id item_code
10 efgh
11 abcd
12 pqrs
13 mnop
I have tried following query
SELECT `t2`.`id`, `t2`.`item_code`, `t1`.`price`,`t1`.`pname`, COUNT(t2.item_code) AS sellers FROM (`table2` as t2) LEFT JOIN `table1` as t1 ON `t1`.`item_code` = `t2`.`item_code` WHERE `t1`.`status` = 1 GROUP BY `t2`.`item_code`
but it returns common values in table1 and table2 with status 1, but I need all records from table2 with price as 0 if nothing match in table1 or status 0 in table1.
Expected output
id item_code price
10 efgh 0
11 abcd 200
12 pqrs 500
13 mnop 0
Any help please.
Thanks,
Not sure about your current query which is having count and group by however you can do as below
select
t2.id,
t2.item_code,
case
when t1.status = 1 then t1.price
else 0
end as price
from table2 t2
left join table1 t1 on t1.item_code = t2.item_code
Now note that if table1 has multiple matching values from table2 in that case we may need grouping data.
Try below query:
SELECT `t2`.`id`, `t2`.`item_code`, `t1`.`price`,`t1`.`pname`, COUNT(t2.item_code) AS sellers FROM (`table2` as t2) LEFT JOIN (select * from table1 where status = 1)t1 ON `t1`.`item_code` = `t2`.`item_code` GROUP BY `t2`.`item_code`
Move the part of the WHERE clause that checks the left joined table to the ON clause
SELECT `t2`.`id`, `t2`.`item_code`, COALESCE(`t1`.`price`, 0),`t1`.`pname`, COUNT(t2.item_code) AS sellers
FROM (`table2` as t2)
LEFT JOIN `table1` as t1
ON `t1`.`item_code` = `t2`.`item_code`
AND`t1`.`status` = 1
GROUP BY `t2`.`item_code`

Group dates based on variable periods

i have two tables as follows------
table-1
CalenderType periodNumber periodstartdate
1 1 01-01-2013
1 2 11-01-2013
1 3 15-01-2013
1 4 25-01-2013
2 1 01-01-2013
2 2 15-01-2013
2 3 20-01-2013
2 4 25-01-2013
table2
Incidents Date
xyz 02-01-2013
xxyyzz 03-01-2013
ccvvb 12-01-2013
vvfg 16-01-2013
x3 17-01-2013
x5 24-01-2013
Now i want to find out the number of incidents took place in a given period(the Calendar type may change on runtime like)
the query should look something like this
select .......
from ......
where CalendarType=1
which should return
CalendarType PeriodNumber Incidents
1 1 2
1 2 1
1 3 3
1 4 0
can someone suggest me an approach or any method how this can be achieved.
Note:each period is variable in size.peroid1 may have 10 days period2 may have 5 days etc.
I think this does what you want, although I don't understand how you arrived at your sample output:
select t.CalenderType, t.periodNumber, count(*) as Incidents
from Table1 t
inner join (
select t2.Date, t2.Incidents, max(t1.periodstartdate) as PeriodStartDate
from Table2 t2
inner join Table1 t1 on t2.Date >= t1.periodstartdate
where CalenderType = 1
group by t2.Date, t2.Incidents
) a on t.periodstartdate = a.PeriodStartDate
where CalenderType=1
group by t.CalenderType, t.periodNumber
SQL Fiddle Example
Try this, a bit more general solution,SQLFiddle (Thanks RedFilter for schema):
SELECT t1.CalenderType, t1.periodNumber, count(Incidents)
FROM Table1 t1, Table1 t11, Table2
WHERE
(
(
t1.CalenderType = t11.CalenderType
AND t1.periodNumber = t11.periodNumber - 1
AND Date BETWEEN t1.periodstartdate AND t11.periodstartdate
)
OR
(
t1.periodNumber = (SELECT MAX(periodNumber) FROM Table1 WHERE t1.CalenderType = CalenderType)
AND Date > t1.periodstartdate
)
)
GROUP BY t1.CalenderType, t1.periodNumber
ORDER BY t1.CalenderType, t1.periodNumber