Need to rewrite query to use max function in a where clause - mysql

Query being used at this time:
update metrics.time_created
set cumu_count = (
select count(*)
from perf_stats.time
where date(insert_datetime)='2015-12-18'
)
where id=max(id);
I get an "invalid use of group function" here -- how can I rewrite this to keep the same logic? I have to update the most recent row in the metrics.time_created table.

Try this:
update metrics.time_created a
set cumu_count = (
select count(*)
from perf_stats.time
where date(insert_datetime)='2015-12-18'
)
where exists (
select 1
from (select max(id) as maxid from metrics.time_created) t
where maxid = a.id
);
Example demo: http://sqlfiddle.com/#!9/6bc3cd/1
EDIT:
Based on comment, here's the change
update metrics.time_created a
set cumu_count =
(
select count(*)
from perf_stats.time pt
where exists
(
select 1
from (select max(curr_date) as mcd from metrics.time_created) x
where mcd = date(insert_datetime)
)
)
where exists
(
select 1
from (select max(id) as maxid from metrics.time_created) t
where maxid = a.id
);
Example demo: http://sqlfiddle.com/#!9/fcc91a/1

You can use self join something like this :
update metrics.time_created as t1
inner join (
select max(id) as id
from metrics.time_created
) as t2 on t1.id = t2.id
set cumu_count = (
select count(*)
from perf_stats.time
where date(insert_datetime)='2015-12-18'
)

If you are trying to update one row with the maximum id, then you can use order by and limit:
update metrics.time_created
set cumu_count = (select count(*)
from perf_stats.time
where date(insert_datetime) = '2015-12-18'
)
order by id desc
limit 1;

Related

Referring to CTE in WHERE condition of UPDATE

I'm trying to run a query like this:
WITH cte AS
(
SELECT id, category, SUM(amount) AS sum_amount FROM t1 GROUP BY id, category
)
UPDATE table SET amount = cte.sum_amount WHERE id = cte.id;
However, I keep getting the error
Unknown column 'cte.id in WHERE clause'
Does anyone know how I can refer to my common table expression in the UPDATE query, or otherwise, rewrite it?
You can try below
WITH cte AS
(
SELECT id, SUM(amount) AS sum_amount FROM t1 GROUP BY category
)
UPDATE T
SET T.sum_amount= CT.sum_amount
FROM table T
JOIN cte CT
ON T.id = CT.id
Alternate way with Temporary table, you can read about CTE and Temporary Table
Temporary table:
SELECT id, category, SUM(amount) AS sum_amount
INTO #temp
FROM t1 GROUP BY id, category
Update query with temp table:
UPDATE OT
SET OT.sum_amount= TT.sum_amount
FROM table OT
JOIN #temp TT
ON OT.id = TT.id
CTE:
WITH cte AS
(
SELECT id, category, SUM(amount) AS sum_amount FROM t1 GROUP BY id,category
)
UPDATE T
SET T.sum_amount= CT.sum_amount
FROM table T
JOIN cte CT
ON T.id = CT.id

How to get the maximum and minimum values in each group as well as their times?

Let's say I have a table MyTable with the columns Id, NumericValue and UTCTimestamp. I'm trying to group the results of my table MyTable by the hour of their timestamp and return the maximum NumericValuefor each group with its associated timestamp as well as the minimum NumericValue for each group with its associated timestamp value.
For now, I'm able to achieve the first part of my problem with the following query:
SELECT
HOUR(t.UTCTimestamp) AS `Hour`,
t.NumericValue AS MaximumValue,
t.UTCTimestamp AS MaximumValueTime
FROM MyTable t
INNER JOIN (
SELECT HOUR(t2.UTCTimestamp) AS `Hour`, MAX(t2.NumericValue) AS NumericValue
FROM MyTable t2
GROUP BY HOUR(t2.UTCTimestamp)
) maxNumericValue ON HOUR(t.UTCTimestamp) = maxNumericValue.`Hour` AND t.NumericValue = maxNumericValue.NumericValue
GROUP BY HOUR(t.UTCTimestamp);
Which was inspired by this answer.
Here's an MVCE.
How could I also show the minimum value for each group as well as the timestamp associated to it?
Starting from MySQL 8.0 you could use ROW_NUMBER:
WITH cte AS (
SELECT *,ROW_NUMBER() OVER(PARTITION BY HOUR(UTCTimestamp)
ORDER BY UTCTimestamp ASC) AS rn
,ROW_NUMBER() OVER(PARTITION BY HOUR(UTCTimestamp)
ORDER BY UTCTimestamp DESC) AS rn2
FROM MyTable
)
SELECT HOUR(c1.UTCTimestamp),
c1.ID, c1.NumericValue, c1.UTCTimestamp, -- min row
c2.ID, c2.NumericValue, c2.UTCTimestamp -- max row
FROM cte c1
JOIN cte c2
ON HOUR(c1.UTCTimestamp) = HOUR(c2.UTCTimestamp)
AND c1.rn=1
AND c2.rn2=1
ORDER BY HOUR(c1.UTCTimestamp) ASC;
DBFiddle Demo
You can join to MyTable twice (and only use one aggregating subquery)
SELECT bounds.`Hour`
, minT.NumericValue AS MinValue
, minT.UTCTimestamp AS MinTime
, maxT.NumericValue AS MaximumValue
, maxT.UTCTimestamp AS MaximumValueTime
FROM (
SELECT HOUR(t2.UTCTimestamp) AS `Hour`
, MAX(t2.NumericValue) AS maxValue
, MIN(t2.NumericValue) AS minValue
FROM MyTable t2
GROUP BY HOUR(t2.UTCTimestamp)
) bounds
LEFT JOIN MyTable minT ON bounds.`Hour` = HOUR(minT.UTCTimestamp)
AND bounds.minValue = minT.NumericValue
LEFT JOIN MyTable maxT ON bounds.`Hour` = HOUR(maxT.UTCTimestamp)
AND bounds.maxValue = maxT.NumericValue
;
Apply the same technique but with minimum:
select a.*, b.MinimumValueTime from (
SELECT
HOUR(t.UTCTimestamp) AS `Hour`,
t.NumericValue AS MaximumValue,
t.UTCTimestamp AS MaximumValueTime
FROM MyTable t
INNER JOIN (
SELECT HOUR(t2.UTCTimestamp) AS `Hour`, MAX(t2.NumericValue) AS NumericValue
FROM MyTable t2
GROUP BY HOUR(t2.UTCTimestamp)
) maxNumericValue ON HOUR(t.UTCTimestamp) = maxNumericValue.`Hour` AND t.NumericValue = maxNumericValue.NumericValue
GROUP BY HOUR(t.UTCTimestamp))a
join
(
SELECT
HOUR(t.UTCTimestamp) AS `Hour`,
t.NumericValue AS MinimumValue,
t.UTCTimestamp AS MinimumValueTime
FROM MyTable t
INNER JOIN (
SELECT HOUR(t2.UTCTimestamp) AS `Hour`, MIN(t2.NumericValue) AS NumericValue
FROM MyTable t2
GROUP BY HOUR(t2.UTCTimestamp)
) minNumericValue ON HOUR(t.UTCTimestamp) = minNumericValue.`Hour` AND t.NumericValue = minNumericValue.NumericValue
GROUP BY HOUR(t.UTCTimestamp))b on a.hour=b.hour

compare two values in sql with eachother

I have a database of magento with double images, I want to delete those but first i got to detect them with a sql query.
I have tried this code
select t1.VALUE from catalog_product_entity_media_gallery t1
join catalog_product_entity_media_gallery t2 on (t1.value = t2.value)
this one:
select * from catalog_product_entity_media_gallery where value=value
and this one:
select
*
from
(
select
value
from
catalog_product_entity_media_gallery
group by
value
having count(*) > 1
) as t
inner join catalog_product_entity_media_gallery on (
catalog_product_entity_media_gallery.value = t.value
)
the first gives an error and the second- and third one gives back every product.
Give this one a try:
select
*
from (
select
entity_id,attribute_id,value,
MIN(value_id) value_id
from catalog_product_entity_media_gallery
group by
entity_id,attribute_id,value
having COUNT(*) > 1
) A1
inner join catalog_product_entity_media_gallery A2 on
A1.entity_id = A2.entity_id and
A1.attribute_id = A2.attribute_id and
A1.value = A2.value and
A1.value_id = A2.value_id
You can just get the min id by value, then except the other records:
select
*
from catalog_product_entity_media_gallery t1
where exists
( select * from
(select value, min(value_id) as min_value_id
from catalog_product_entity_media_gallery
group by value
) as t2
where t1.value=t2.value and t1.value_id=t2.min_value_id
)
If you want delete the duplicated rows, change exists to not exists.
delete
from catalog_product_entity_media_gallery t1
where not exists
( select * from
(select value, min(value_id) as min_value_id
from catalog_product_entity_media_gallery
group by value
) as t2
where t1.value=t2.value and t1.value_id=t2.min_value_id
)

How Can I Grab The "COUNT" From A Correlated Subquery?

I've got a query that looks like..
SELECT id_b FROM id_table
WHERE id_a = ?
AND (
SELECT COUNT(*) AS rowCount FROM other_table
WHERE id = id_b
) > 0;
How would I retrieve the value rowCount?
EDIT: This is a MYSQL DB
Select A..., Z.RowCount
From id_table As A
Cross Join (
Select Count(*) As RowCount
From other_table
Where id_b = ?
) As Z
Where A.id_a = ?
And Z.RowCount > 0
Edit
Given your edit, I'm guessing you are trying achieve something akin to:
Select A..., Z.RowCount
From id_table As A
Join (
Select id_b, Count(*) As RowCount
From other_table
Group By id_b
) As Z
On Z.id_b = A.id_b
Where A.id_a = ?
And Z.Cnt > 0
You could try:
SELECT (
SELECT COUNT(*) AS rowCount FROM other_table
WHERE id_b = ?
) AS rowCount, id_b FROM id_table
WHERE id_a = ?
AND (
SELECT COUNT(*) AS rowCount FROM other_table
WHERE id_b = ?
) > 0;
That would work in SQL Server

UPDATE table with SELECT from another but with a field being SUM(someField)

Basically I have something like this:
UPDATE
Table
SET
Table.col1 = other_table.col1,
FROM
Table
INNER JOIN
other_table
ON
Table.id = other_table.id
The problem is that I would like to update col1 with the select being like:
SELECT SUM(col1) FROM other_table WHERE Table.id = other_table.id AND period > 2011
Edit
Correct Answer:
UPDATE bestall
INNER JOIN (SELECT bestid,SUM(view) as v,SUM(rawView) as rv
FROM beststat
WHERE period > 2011 GROUP BY bestid) as t1
ON bestall.bestid = t1.bestid
SET view = t1.v, rawview = t1.rv
You can't use aggregates directly in a set clause. One way around that is a subquery:
update your_table as yt
left join
(
select id
, count(*) as cnt
from other_table
where period < 4
group by
id
) as ot
on yt.id = ot.id
set col1 = coalesce(ot.cnt,0)
Example at SQL Fiddle.