H2 - Setting variable does not work as expected - sql

I am using h2 to generate some data for tests.
I have a select statement, that selects a random row in a table.
Within the select statement I set a variable called 'K' with the SET function (http://h2database.com/html/functions.html#set).
In a second statement within the same session I try to read / get the current value of the variable.
To get a reproducible result I use SYSTEM_RANGE(1,10) in the select statement below. I use the h2 web console to execute the statements.
If I set the variable like in the following statement
SET #K = SELECT X FROM SYSTEM_RANGE(1,10) ORDER BY RANDOM() LIMIT 1;
and I execute a subsequent VALUES statement
VALUES(#K)
it works as expected. The variable K has been set to a random value. Subsequent executions of both these statements show, that value of the variable changes randomly.
I would like to assign the variable within a select statement. Setting the variable as shown above does not help in reaching my goal.
This does not work as expected
SELECT SET(#K,X) FROM SYSTEM_RANGE(1,10) ORDER BY RANDOM() LIMIT 1;
VALUES(#K); -- value of K is different than result of above select
-- subsequent executions show that the result of the select changes as expected
— but the result of the values statement and thus the value of K does not change
I would expect the result of the select statement to be the same as the value of the variable, but they are not. Subsequent executions of both statements show, that the select statements delivers randomly selected results, but the values statement delivers the same / a constant integer.

(I tried a little....) and it is possible (not to call RAND, anytime you call VALUES):
SET #K = FLOOR(RAND() * 9) + 1;
VALUES(#K);
"Just omit" the select statement in SET

Related

json_remove is removing the wrong value from array on second run

I am trying to remove a value from a json array, however I am having issues.
First I insert the array into into the table like so:
INSERT into demo (hint) VALUES ('["Hello","World"]');
Next when I run this query, the World value gets removed which is what is supposed to happen. However if I run it a second time, then the Hello value gets removed which is not supposed to happen. What am I doing wrong, or what is a better way to remove items from a json array?
UPDATE demo SET hint = json_remove(
hint,
(SELECT json_each.fullkey FROM demo, json_each(demo.hint) WHERE json_each.value = 'World')
);
select * from demo;
The subquery that you use as the path argument of json_remove() returns null the 2nd time that you execute the update statement because there is no "World" in the json array.
In this case json_remove() also returns null.
If your version of SQLite is 3.33.0+ you can use the UPDATE...FROM syntax:
UPDATE demo AS d
SET hint = json_remove(d.hint, j.fullkey)
FROM json_each(d.hint) AS j
WHERE j.value = 'Hello';

Randomly insert 1 of 3 declared variables

I have three variables that are declared and have an integer value assigned to them.
I am trying to randomly assign the integer value to a field in an UPDATE statement, but get an error.
This is statement I am trying to execute:
FOR user_record IN (SELECT * FROM users_to_add) LOOP
UPDATE
customer."user"
SET
primary_site_id = ({site_GRO, site_WHS, site_SHR}[])[ceil(random()*3)],
WHERE
userid = (SELECT userID FROM customer.user
WHERE emailaddress=user_record.email_address);
END LOOP;
I am getting:
SyntaxError: syntax error at or near "{"
This same format works if the value being randomly selected is a string but since these are variables, the inside curly brackets can't be enclosed in quotes.
Use an ARRAY constructor instead of the (invalid) array literal.
(ARRAY[site_GRO, site_WHS, site_SHR])[ceil(random()*3)]
However, a set-based solution is typically more efficient than looping:
UPDATE customer."user" u
SET primary_site_id = CASE trunc(random()*3)::int
WHEN 0 THEN site_gro -- your variables here
WHEN 1 THEN site_whs
WHEN 2 THEN site_shr
END
FROM users_to_add ua
WHERE u.userid = ua.email_address;
Should achieve the same. Works inside a PL/pgSQL block or as standalone SQL DML command (then you need to interpolate variable values yourself).
A single multi-row UPDATE is much cheaper than many updates in a loop.
trunc() is slightly more correct than ceil(), as random() returns a value in the domain [0,1) (1 excluded). It's also faster.
And a CASE construct is substantially faster than building an array just to extract a single element from it.
Asides:
Avoid reserved words like user as identifiers. Always requires double-quoting, and can lead to confusing errors when forgotten.
Also avoid random capitalization in identifiers. This goes for SQL as well as for PL/pgSQL. See:
Are PostgreSQL column names case-sensitive?
Perhaps you can try splitting the index and array out into their own vars?
FOR user_record IN (SELECT * FROM users_to_add) LOOP
a := ARRAY[site_GRO, site_WHS, site_SHR];
i := ceil(random()*3);
UPDATE
customer."user"
SET
primary_site_id = a[i]
WHERE
userid = (SELECT userID FROM customer.user WHERE emailaddress=user_record.email_address);
END LOOP;

How to anonymize data in SQL?

I need to anonymize a variable in SQL data (VAR NAME = "ArId").
The variable contains 10 numbers + 1 letter + 2 numbers. I need to randomize the 10 first numbers and then keep the letter + the last two numbers.
I have tried the rand() function, but this randomize the whole value.
SELECT TOP 1000 *
FROM [XXXXXXXXXXX].[XXXXXXXXXX].[XXXXX.TEST]
I have only loaded the data.
EDIT (from "answer"):
I have tried: UPDATE someTable
SET someColumn = CONCAT(CAST(RAND() * 10000000000 as BIGINT), RIGHT(someColumn, 3))
However as i am totally new to SQL i don't know how to make this work. I put 'someColumn = new column name for the variable i am crating. RIGHT(someColumn) = the column i am changing. When i do that i get the message that the right function requires 2 arguments??
Example for Zohar: I have a variable containing for example: 1724981628R01On all these values in this variable i would like to randomize the first 10 letters and keep the last three (R01). How can i do that?
A couple things. First, your conversion to a big int does not guarantee that the results has the right number of characters.
Second, rand() is constant for all rows of the query. Try this version:
UPDATE someTable
SET someColumn = CONCAT(FORMAT(RAND(CHECKSUM(NEWID())
), '0000000000'
),
RIGHT(someColumn, 3)
);

SELECT a cell and UPDATE at the same time?

I've got a SQL Server table in which I have a column where I would like to select the current value and increment by one, is there a way to do this in a single query? This in order to mitigate the chance, however small it might be, that someone else gets the same number.
Something along the lines of this pseudo code:
SELECT NumSeriesCurrent
FROM NumSeries
(UPDATE NumSeries SET NumSeriesCurrent = NumSeriesCurrent+1)
WHERE NumSeriesKey='X'
To update the value and get the value in NumSeriesCurrent previous to the update you can use
UPDATE NumSeries
SET NumSeriesCurrent += 1
OUTPUT DELETED.NumSeriesCurrent
WHERE NumSeriesKey='X'

If a SELECT "string" INTO var1 with a WHERE return no lines, does the string still get moved into var1?

MOVE "Y" TO :LKG-RETURN
EXEC SQL
SELECT "N"
INTO :LKG-RETURN
FROM SOME_TABLE
WHERE SOME_COLUMN = :SOME_VAR
END-EXEC.
This is a part of a SQLCOBOL program where I need to check some variable in a database to see if the main program must run or not a job. By default I put "Y" into the return value but if the select return lines the job must not be run, so I put "N" into it. My question is:
If the select return 0 lines (which mean the job must be run), does it still move "N" to :LKG-RETURN? If it does, what could be my options to achieve the desired result?
Thanks.
The normal SQL behaviour would be that the value is NOT returned. but I've never used SQLCOBOL to be able to test this. And whenever I have even the remotest hesitation, I test.
In the absence of the ability to test, this will always return a value...
SELECT COUNT(*)
INTO :LKG-RETURN
FROM SOME_TABLE
WHERE SOME_COLUMN = :SOME_VAR
-- 0 = no hits
Or possibly...
SELECT
CASE WHEN EXISTS (SELECT * FROM SOME_TABLE WHERE SOME_COLUMN = :SOME_VAR)
THEN 'Y' ELSE 'N' END
But, seriously, you need to find a way to test developments in your work environment.
I do not envy how difficult it must be where you work. I hope this works out for you.