I use this code in MySQL to order by 'anotherColumn' and then get the row number of 'myColumn' and then I perform a calculation and set 'myColumn' to the result:
SET #c = (SELECT COUNT(*) FROM myTable); SET #rownum = 0; UPDATE myTable SET myColumn = #c * (#rownum:= 1 + #rownum) ORDER BY anotherColumn DESC LIMIT 100000;
I'm trying to achieve the same thing in Postgresql but am getting a lot of errors. I have:
SET c = (SELECT COUNT(*) FROM myTable); SET rownum = 0; UPDATE myTable SET myColumn = c * (rownum:= 1 + rownum) ORDER BY anotherColumn DESC LIMIT 100000;
.. but it gives me an error at the first parenthesis. If I remove those parenthesis like this:
SET c = SELECT COUNT(*) FROM myTable; SET rownum = 0; UPDATE myTable SET myColumn = c * (rownum:= 1 + rownum) ORDER BY anotherColumn DESC LIMIT 100000;
.. then it gives me an error at the SELECT. If I just set c to equal 0, I get an error way down at the ORDER. Does anyone know how to convert my code from MySQL to PostgreSQL?
This "pattern" in MySQL is typically used to work around the absence of window function.
You don't need variables in Postgres to achieve something like that:
update my_table
set my_column = t.cnt + t.rn
from (
select pk_column,
(select count(*) from my_table) as cnt,
row_number() over (order by another_column) as rn
from my_table
limit 100000
) t
where t.pk_column = my_table.pk_column;
Where pk_column is the primary key column of your table. If you have more than one PK column, you need to use all of them.
Related
I'm trying to get the number of rows in a table or column and place that value inside an equation, like this:
UPDATE myTable
SET myCalculatedColumn = COUNT(*) / (#rownum:= 1 + #rownum)
WHERE 0 = (#rownum:=0)
Unfortunately, I get an error 1111 "Invalid use of group function". I've also tried:
SET #c = COUNT(*);
UPDATE myTable
SET myCalculatedColumn = #c / (#rownum:= 1 + #rownum)
WHERE 0 = (#rownum:=0)
But this produces the same error.
How can I place COUNT(*) (or a programmatically equivalent operation) into an equation?
Join with a subquery that gets the count. You can also initialize the #rownum variable there as well.
UPDATE myTable AS t
CROSS JOIN (SELECT COUNT(*) AS count, #rownum := 0 FROM myTable) AS c
SET myCalculatedColumn = count / (#rownum := 1 + #rownum)
If you don't want to do a cross join, you can use the subquery when setting #c. You just have to tell COUNT(*) what table to count from.
SET #c = (SELECT COUNT(*) FROM myTable);
SET #rownum = 0;
UPDATE myTable
SET myCalculatedColumn = #c / (#rownum:= 1 + #rownum);
Note that the order that it assigns to myCalculatedColumn will be arbitrary and unpredictable unless you also have an ORDER BY clause.
I have the following query script that is resulting in an error:
SET #row_number = 0;
Drop Table If Exists testtable2;
Create Temporary Table testtable2
SELECT
*
FROM
(SELECT
row_names, (#row_number:=#row_number + 1) AS num, date_add(date_time, INTERVAL 1 MINUTE) AS date_time, meter, kw
FROM
testtable
WHERE
DAY(date_time) = 1
AND HOUR(date_time) = 2) AS testtable2
WHERE
MOD(testtable2.num, 2) = 0;
UPDATE testtable
SET
testtable.date_time = testtable2.date_time
WHERE
testtable.row_names = testtable2.row_names;
The error says Error Code: 1054. Unknown column 'testtable2.row_names' in 'where clause'
I created a temporary table that contains the column date_time but my update query fails to recognize that the column exists. I can run something like SELECT * FROM testtable2; and it returns showing that the column is indeed generated with the correct title. Why can my update not recognize this column?
This is your update statement:
UPDATE testtable
SET testtable.date_time = testtable2.date_time
WHERE testtable.row_names = testtable2.row_names;
What is testtable? You have not defined that. You created testtable2. If you do have testtable, then perhaps you want a join:
UPDATE testtable tt JOIN
testtable2 tt2
ON tt.row_names = tt2.row_names
SET tt.date_time = tt2.date_time;
You actually meant to use CREATE TABLE ... AS construct but in your case it's wrongly formed. It should be like below.
Create Temporary Table testtable2 AS
SELECT
*
FROM
(SELECT
row_names, (#row_number:=#row_number + 1) AS num,
date_add(date_time, INTERVAL 1 MINUTE) AS date_time,
meter,
kw
FROM
testtable
WHERE
DAY(date_time) = 1
AND HOUR(date_time) = 2) AS XXX <-- Here
WHERE
MOD(testtable2.num, 2) = 0;
Issue in your case is, your Temporary table and inline view alias are same. name them differently. See edited query.
You can directly JOIN with the inner query and can perform UPDATE like
UPDATE testtable
JOIN (
SELECT
*
FROM
(SELECT
row_names, (#row_number:=#row_number + 1) AS num, date_add(date_time, INTERVAL 1 MINUTE) AS date_time, meter, kw
FROM
testtable
WHERE
DAY(date_time) = 1
AND HOUR(date_time) = 2) AS testtable2
WHERE
MOD(testtable2.num, 2) = 0 ) xx ON testtable.row_names = xx.row_names
SET
testtable.date_time = xx.date_time;
I tried two methods but failed in mysql.
/*see top 50% students, but this sql can't work*/
select * from student_table order by chinese_score desc limit count(*) * 0.5 ;
/*also can't work*/
set #num= floor((select count(*) from test.student_score)*0.5);
select * from student_table order by chinese_score desc limit #num ;
How to solve in mysql?
In Mysql this can be done in a single query using user defined variables.
You can store a value in a user-defined variable in one statement and
refer to it later in another statement. This enables you to pass
values from one statement to another.
SELECT * FROM (
SELECT student_table.*, #counter := #counter +1 AS counter
FROM (SELECT #counter:=0) AS initvar, student_table
ORDER BY student_table.chinese_score DESC
) AS result
WHERE counter < (#counter/2) ORDER BY chinese_score DESC;
I have a query that uses a variable in its where clause:
SET #id = 1;
SELECT
id,
value
FROM myTable
WHERE id = #id;
I would like to run the query for #id values 1 through 100, and then union (or somehow combine) all the loop results into one result set. Is this possible in MySQL, and if so, what is a good approach?
Why would use use a variable for this? Just use a simple where clause:
select id, value
from myTable
where id between 1 and 100;
If, instead, you really want the first 100 rows by id, then use order by and limit:
select id, value
from myTable
order by id
limit 100;
Just use a subquery to get the variable.
And put the where outside
SELECT *
FROM
(
SELECT
#rownumber := if(#rownumber, #rownumber + 1, #rownumber + 1) AS id,
value
FROM myTable
CROSS JOIN (select #rownumber := 0) r
) as T
WHERE id < 100;
Lets say I have these columns
uniqueID|Money|Quantity|MoneyOrder|QuantityOrder
1|23|12||
2|11|9||
3|99|100||
What I want to do is update MoneyOrder and QuantityOrder based on the value of ORDER BY.
So the results would be:
uniqueID|Money|Quantity|MoneyOrder|QuantityOrder
1|23|12|2|1
2|11|90|1|2
3|99|100|3|3
I want the update to operate like an identity column without actually making it an identity column. I know that I could just order by 'x' and the order would be the result but I want to generate a report where you can see the item line by line.
Is something like this possible update mytable set Moneyorder = 'imnotsure' order by MoneyOrder asc ?
SET #rownumber = 0;
update mytable set Moneyorder = (#rownumber:=#rownumber+1)
order by MoneyOrder asc
or to do it in a single query you can try
update mytable target
join
(
select id, (#rownumber := #rownumber + 1) as rownum
from mytable
cross join (select #rownumber := 0) r
order by MoneyOrder asc
) source on target.id = source.id
set Moneyorder = rownum
See answers to this question:
Updating column so that it contains the row position
SET #counter = 0;
UPDATE
my_table
SET MoneyOrder = #counter := #counter + 1
ORDER BY Money;
SET #counter = 0;
UPDATE
my_table
SET QuantityOrder = #counter := #counter + 1
ORDER BY Quantity;