I want to update a column with the rolling average of the product of two other columns, all in the one table.
create table tb (code str, date str, cl float, vo float);
insert into tb values
('BHP', '2020-01-03', 3.25, 1000),
('BHP', '2020-01-04', 3.50, 2000),
('BHP', '2020-01-05', 3.55, 1000),
('CSR', '2020-01-03', 5.55, 1500),
('CSR', '2020-01-04', 5.60, 2000),
('CSR', '2020-01-05', 5.55, 2000),
('DDG', '2020-01-03', 10.20, 4000),
('DDG', '2020-01-04', 10.25, 4500),
('DDG', '2020-01-05', 10.30, 5000);
alter table tb add column dv float;
alter table tb add column avg_dv float;
update tb set dv = (select cl * vo);
select * from tb;
BHP|2020-01-03|3.25|1000.0|3250.0|
BHP|2020-01-04|3.5|2000.0|7000.0|
BHP|2020-01-05|3.55|1000.0|3550.0|
CSR|2020-01-03|5.55|1500.0|8325.0|
CSR|2020-01-04|5.6|2000.0|11200.0|
CSR|2020-01-05|5.55|2000.0|11100.0|
DDG|2020-01-03|10.2|4000.0|40800.0|
DDG|2020-01-04|10.25|4500.0|46125.0|
DDG|2020-01-05|10.3|5000.0|51500.0|
So far, so good. I can select a rolling average -
select code, date, avg(dv)
over (partition by code order by date asc rows 1 preceding)
from tb;
BHP|2020-01-03|3250.0
BHP|2020-01-04|5125.0
BHP|2020-01-05|5275.0
CSR|2020-01-03|8325.0
CSR|2020-01-04|9762.5
CSR|2020-01-05|11150.0
DDG|2020-01-03|40800.0
DDG|2020-01-04|43462.5
DDG|2020-01-05|48812.5
but when I try to put that selection into the avg_vo column of the table I don't get what I was expecting -
update tb set avg_dv =
(select avg(dv)
over (partition by code order by date asc rows 1 preceding)
);
select * from tb;
BHP|2020-01-03|3.25|1000.0|3250.0|3250.0
BHP|2020-01-04|3.5|2000.0|7000.0|7000.0
BHP|2020-01-05|3.55|1000.0|3550.0|3550.0
CSR|2020-01-03|5.55|1500.0|8325.0|8325.0
CSR|2020-01-04|5.6|2000.0|11200.0|11200.0
CSR|2020-01-05|5.55|2000.0|11100.0|11100.0
DDG|2020-01-03|10.2|4000.0|40800.0|40800.0
DDG|2020-01-04|10.25|4500.0|46125.0|46125.0
DDG|2020-01-05|10.3|5000.0|51500.0|51500.0
The avg_dv column has been updated with just the dv values, not the rolling average.
I also tried to adapt the answer here as
update tb
set tb.avg_dv = b.avg_dv
from tb as a inner join
(select code, date, avg(dv)
over (partition by code order by date asc rows 1 preceding)) b
on a.code = b.code and a.date = b.date;
But that just gives me syntax error -
Error: near ".": syntax error
In particular, the reference to "b" in the line
set tb.avg_dv = b.avg_dv
looks like garbage, but I don't know what to replace it with.
Can this be done in a single query?
The code that you tried to adapt in your case uses SQL Server syntax.
If your version of SQLite is 3.33.0+ the correct syntax is:
update tb
set avg_dv = b.avg_dv
from (
select code, date,
avg(dv) over (partition by code order by date asc rows 1 preceding) avg_dv
from tb
) b
where tb.code = b.code and tb.date = b.date;
If you are using a previous version of SQLite that does not support the FROM clause in the UPDATE statement, then you can do it with a CTE:
with cte as (
select code, date,
avg(dv) over (partition by code order by date asc rows 1 preceding) avg_dv
from tb
)
update tb
set avg_dv = (select c.avg_dv from cte c where c.code = tb.code and c.date = tb.date)
Also note that the update statement for the column dv can be written simply:
update tb set dv = cl * vo;
and if your version of SQLite is 3.31.0+, you could create it as generated column so that there is no need for updates:
alter table tb add column dv float generated always as(cl * vo);
Related
I need Only one unique result from tableB.Field to tableA.Field
I am using sdo operator sdo_nn, this is the code:
UPDATE table1 t1
SET t1.fieldA = (SELECT T2.fieldB,SDO_NN_DISTANCE(1) distance
FROM table1 T1, table2 T2
WHERE
(sdo_nn(t1.geometry,t2.geometry,'SDO_NUM_RES=1',1)= 'TRUE')
ORDER BY DIST
)
WHERE EXISTS(
SELECT 1
FROM table2 t2
WHERE sdo_nn(t1.geometry, t2.geometry,'SDO_NUM_RES=1',1)='TRUE'
AND(t2.cell_name = 'string1' or t2.cell_name = string2')AND t1.fieldA = NULL
);
In the select sentence of the subquery i get an error because i only use one field(t1.fieldA), but in the sentence i use the operator SDO_NN_DISTANCE(1) and the sql developer count this operator like another field. What is the correct way to write this sentence? I only use sql because i need to insert this code in vba
Thanks!!!
Obviously, you can't (simplified)
set t1.fieldA = (t2.fieldB, distance) --> you want to put two values into a single column
Therefore, get fieldB alone from the subquery which uses analytic function (row_number) to "sort" rows by sdo_nn_distance(1) desc; then get the first row's fieldB value.
Something like this (I hope I set the parenthesis right):
UPDATE table1 t1
SET t1.fieldA =
(SELECT x.fieldB --> only fieldB
FROM (SELECT T2.fieldB, --> from your subquery
SDO_NN_DISTANCE (1) distance,
ROW_NUMBER ()
OVER (ORDER BY sdo_nn_distance (1) DESC) rn
FROM table1 T1, table2 T2
WHERE (sdo_nn (t1.geometry,
t2.geometry,
'SDO_NUM_RES=1',
1) = 'TRUE')) x
WHERE rn = 1) --> where RN = 1
WHERE EXISTS
(SELECT 1
FROM table2 t2
WHERE sdo_nn (t1.geometry,
t2.geometry,
'SDO_NUM_RES=1',
1) = 'TRUE'
AND ( t2.cell_name = 'string1'
OR t2.cell_name = 'string2')
AND t1.fieldA IS NULL);
Table three columns id, numers1 and numbers2. We need to summarize numers1 and numbers2 but the first row to the second row numers1 numers2 the second with the third and forth etc.:
CREATE TABLE tb1 (id INTEGER PRIMARY KEY AUTOINCREMENT,numbers1,numbers2);
INSERT INTO tb1 (numbers1,numbers2) values(1,10);
INSERT INTO tb1 (numbers1,numbers2) values(2,20);
INSERT INTO tb1 (numbers1,numbers2) values(3,30);
INSERT INTO tb1 (numbers1,numbers2) values(4,40);
INSERT INTO tb1 (numbers1,numbers2) values(5,50);
I want to get as:
21
32
43
54
with the reference of getting the correct row index per record here:
How to use ROW_NUMBER in sqlite
I was able to create the required result with the following query:
SELECT
num1 + coalesce(b_num2, 0)
FROM(
SELECT
num1,
(select count(*) from test as b where a.id >= b.id) as cnt
FROM test as a) as a
LEFT JOIN
(SELECT num2 as b_num2,
(select count(*) from test as b where a.id >= b.id) as cnt
FROM test as a
) as b
ON b.cnt = a.cnt + 1
Explanation:
by joining two same table of similar record index, then merge the next record with the current record and then sum num1 of current record with num2 of next record, I do not know how you want to deal with the last row as it does not have a next row so I assume it to add nothing to have a result of just the value of num1
Result:
For one row with a specific ID x, you can get values from the next row by searching for ID values larger than x, and taking the first such row:
SELECT ...
FROM tb1
WHERE id > x
ORDER BY id
LIMIT 1;
You can then use this as a correlated subquery to get that value for each row:
SELECT numbers1 + (SELECT T2.numbers2
FROM tb1 AS T2
WHERE T2.id > T1.id
ORDER BY T2.id
LIMIT 1) AS sum
FROM tb1 AS T1
WHERE sum IS NOT NULL; -- this omits the last row, where the subquery returns NULL
Example:
It does not work.
UPDATE column_name SET rownum FROM table_name
This work!
UPDATE table_name SET column_name = rownum;
This works but the update is performed incorrectly
SELECT * FROM table_name ORDER BY column_name;
UPDATE table_name SET column_name = rownum;
I wish the following update behavior:
Note:'rownum ' It is not a physical column of the table
/*
pc_comentario = tableName
cod_comentario = columnName (Reference column for sorting)
dtc_andamento = columnDay (Reference column to update the "columnName" according to the order of this column)
*/
rownum | columnName | columnDay
1 1 day 1
2 5 day 5
3 7 day 2
After change with update
rownum | columnName (Update this column) | columnDay (sort by this column)
1 1 day 1
2 2 day 2
3 3 day 5
ALMOST DONE! this column 'cod_comentario_1 "which was materialized in RAM is correct. I need this column" cod_comentario_1 "that does not exist in the table is acknowledged in the consultations with java.
SELECT cod_comentario, dtc_andamento, cod_processo ,
ROW_NUMBER()
OVER (PARTITION BY cod_processo
ORDER BY dtc_andamento) cod_comentario_1
FROM pc_comentario
upadate do not work this way:
UPDATE (
SELECT cod_processo
ROW_NUMBER()
OVER (PARTITION BY cod_processo
ORDER BY dtc_andamento)cod_comentario_1
FROM pc_comentario
) SET cod_comentario_1)
order by Seq
I must enter the values of this consultation in a new column that I created
SELECT
ROW_NUMBER()
OVER (PARTITION BY cod_processo
ORDER BY dtc_andamento DESC)
FROM pc_comentario
Try:
UPDATE table_name
SET column_name = rownum
Shouldn't it be like below rather; I believe UPDATE statement has no FROM clause
UPDATE table_name SET column_name = rownum;
Again, it will work only if rownum is an existing column in your table. If you are trying to use Oracle rownum instead then consider using row_number() function rather
update table_name set column_name =
select rn from ( select column_name, row_number() over (order by column_name) rn
from table_name ) xx;
As you state yourself, rownum is a virtual column. It assigns a sequential value to each row of a particular result set. Which means that the row number of a row could be completely different in the result set of a different query.
If you really want to show the row number as part of the result set, specify it as you would any column:
select rownum as columnName, columnDay
from table
order by ...;
I am trying to run query
select * from OS_Historystep where step_name = '011' and finish_date = max(finish_date) ;
But i am getting error that
ORA-00934: group function is not allowed here
00934. 00000 - "group function is not allowed here"
*Cause:
*Action:
Error at Line: 12 Column: 72
what i am doing wrong?
Thanks
You can't use an aggregate in a where clause. Also, you can't mix non-aggregated data and aggregated data from the same column in a single select. You'll need to use a sub-query:
select *
from OS_Historystep hs1
where step_name = '011'
and finish_date = (select max(finish_date)
from OS_Historystep hs2
where hs2.step_name = hs1.step_name);
you cannot reference an aggregate like that. you would either have to put a sub query up like below (assuming you wanted the max(finish_date) to mean the max finish date for step 011 and not the max finish date in the whole table (which may return no rows):
select *
from OS_Historystep
where step_name = '011'
and finish_date = (select max(finish_date)
from OS_Historystep
where step_name = '011');
or use an analytic function
select *
from (select s.*, rank() over (partition by step_name order by finish_date desc) rnk
from OS_Historystep s
where step_name = '011')
where rnk = 1;
If I query:
select max(date_created) date_created
on a datefield in PL/SQL (Oracle 11g), and there are records that were created on the same date but at different times, Max() returns only the latest times on that date. What I would like to do is have the times be ignored and return ALL records that match the max date, regardless of their associated timestamp in that column. What is the best practice for doing this?
Edit: what I'm looking to do is return all records for the most recent date that matches my criteria, regardless of varying timestamps for that day. Below is what I'm doing now and it only returns records from the latest date AND time on that date.
SELECT r."ID",
r."DATE_CREATED"
FROM schema.survey_response r
JOIN
(SELECT S.CUSTOMERID ,
MAX (S.DATE_CREATED) date_created
FROM schema.SURVEY_RESPONSE s
WHERE S.CATEGORY IN ('Yellow', 'Blue','Green')
GROUP BY CUSTOMERID
) recs
ON R.CUSTOMERID = recs.CUSTOMERID
AND R.DATE_CREATED = recs.date_created
WHERE R.CATEGORY IN ('Yellow', 'Blue','Green')
Final Edit: Got it working via the query below.
SELECT r."ID",
r."DATE_CREATED"
FROM schema.survey_response r
JOIN
(SELECT S.CUSTOMERID ,
MAX (trunc(S.DATE_CREATED)) date_created
FROM schema.SURVEY_RESPONSE s
WHERE S.CATEGORY IN ('Yellow', 'Blue','Green')
GROUP BY CUSTOMERID
) recs
ON R.CUSTOMERID = recs.CUSTOMERID
AND trunc(R.DATE_CREATED) = recs.date_created
WHERE R.CATEGORY IN ('Yellow', 'Blue','Green')
In Oracle, you can get the latest date ignoring the time
SELECT max( trunc( date_created ) ) date_created
FROM your_table
You can get all rows that have the latest date ignoring the time in a couple of ways. Using analytic functions (preferrable)
SELECT *
FROM (SELECT a.*,
rank() over (order by trunc(date_created) desc) rnk
FROM your_table a)
WHERE rnk = 1
or the more conventional but less efficient
SELECT *
FROM your_table
WHERE trunc(date_created) = (SELECT max( trunc(date_created) )
FROM your_table)