Using Set and Unset in one N1QL (Couchbase) - n1ql

I have this Document whwre I need to Unset orderState array and set profileState to "AVAILABLE".
I am trying this N1QL statement but it throws error on END.
update ${BUCKET} as b unset b.orderState WHERE b.type = "ao.los:pro" and
profileInformation.iccid="${ICCID}" and profileInformation.customerId is not
missing limit 1 END, SET b.profileState="AVAILABLE" END returning *;

UPDATE default AS b
SET b.profileState="AVAILABLE" UNSET b.orderState
WHERE b.type = "ao.los:pro"
AND b.profileInformation.iccid = "ICCID"
AND b.profileInformation.customerId IS NOT MISSING
LIMIT 1
RETURNING *;
The syntax of update: https://docs.couchbase.com/server/6.0/n1ql/n1ql-language-reference/update.html

Related

SELECT SCOPE_IDENTITY() to return the last inserted ID

There are a few answers about this problem, but my question is about the particular code I have.
I'm trying to get the last inserted ID of this query executing on VBA code.
Public Function Execute(cQry As excfw_dbQuery) As ADODB.Recordset
If pConn.State = 0 Then
OpenConnection
End If
qry = "INSERT INTO [some really long query, which actually works]; SELECT SCOPE_IDENTITY()"
On Error Resume Next
Dim rs As ADODB.Recordset
Set rs = New ADODB.Recordset
rs.Open qry, pConn 'also tried with adOpenKeyset, adLockOptimistic
'some error handling code which is not related to the issue
Set rs = rs.NextRecordset() 'also tried without moving onto the next recordset
pInsertedId = rs.Fields(0).Value
Set Execute = rs 'this is just to pass the query result for SELECT queries
End Function
This should save the last inserted ID on the pInsertedId variable, but instead I get 0 each time I insert a row. The weird thing is, when I copy and paste the same code into the SSMS, it works.
I might just get away with inserting some unique data to some unused column of the database and querying through that.
--UPDATE--
I've just noticed that when running a SELECT query, rs object remains open until it goes out of scope. Here is a screenshot of the watch section:
on an insert statement instead, it gets closed as soon as the query gets executed:
You can explicitly save the results of the insert statement by using an output clause and return the results with a select:
qry =
"declare #Ids as ( Id Int );" +
"insert into MyTable ( Name ) " + ' Assuming Id is an identity column.
"output Inserted.Id into #Ids " +
"values ( #Name );" +
"select Id from #Ids;"
From the documentation for output:
INSERTED Is a column prefix that specifies the value added by the
insert or update operation. Columns prefixed with INSERTED reflect the
value after the UPDATE, INSERT, or MERGE statement is completed but
before triggers are executed.
You can use an output clause to get any data from the rows (Note plural.), e.g. identity column values for newly inserted rows. Output can be used with insert, update, delete and merge and provides access to both before and after values in the case of update. A tool well worth having in your pocket.
As it turns out, the table that I'm trying to insert to has multiple triggers attached to it. So, the query which includes the SELECT SCOPE_IDENTITY(); is actually 4th query. I had to move 4 queries forward in order to get the correct scope. How I pulled that off programatically is as follows. Not very clean (and possibly not the best way to do it), but does the job for me.
I basically go ahead to next recordset until there is none left, which I detect by checking the error number 91 (Object variable or with block variable not set)
Public Function Execute(cQry As excfw_dbQuery) As ADODB.Recordset
If pConn.State = 0 Then
OpenConnection
End If
qry = "INSERT INTO [some really long query, which actually works]; SELECT SCOPE_IDENTITY()"
On Error Resume Next
Dim rs As ADODB.Recordset
Set rs = New ADODB.Recordset
rs.Open cQry.Query, pConn, adOpenKeyset, adLockOptimistic
'some error handling code which is not related to the issue
On Error Resume Next
'begin loop
Do
'go to next recordset
Set rs = rs.NextRecordset()
'if we're getting error n. 91, it means
'recordsets are exhausted, hence we're getting
'out of the loop
If Err.Number = 91 Then
Err.Clear
Exit Do
End If
'if we are not out of recordsets, check the
'result of the query. If it is bigger then zero,
'it means we hit the jackpot.
If rs.Fields(0).Value > 0 Then
pInsertedId = rs.Fields(0).Value
End If
Loop
On Error GoTo 0
End Function
Again, not the cleanest, nor the most correct way to do it, but did the trick. I'm open for any improvements or suggestions.

Using bash, awk or sed to templatize a CSV file into a SQL file

I will have a CSV file (say, ids.csv) that I need to ETL into a SQL script (say, update_products.sql). The CSV will be headerless and will consist of comma-delimited numbers (product IDs in a database), for instance:
29294848,29294849,29294850,29294851,29294853,29294857,29294858,29294860,29294861,29294863,29294887,29294888,
29294889,29294890,29294891,29294892,29294895,29294897,29294898,29294899,29294901,29294903,29294912,29294916
Starting with a SQL "template" file (template.sql) that looks something like this:
UPDATE products SET quantity = 0 WHERE id = %ID%;
I'm looking for a way via bash, awk, sed (or any other type of shell scripting tool), to templatize %IDS% with the values in the CSV, hence turning the generated SQL into something like:
UPDATE products SET quantity = 0 WHERE id = 29294848;
UPDATE products SET quantity = 0 WHERE id = 29294849;
UPDATE products SET quantity = 0 WHERE id = 29294850;
... etc, for all the IDs in the CSV...
Super flexible here:
Don't care which tool gets the job done (awk, sed, bash, whatever...as long as I can run it from the command line)
Don't necessarily NEED a template file (template.sql) to start with, perhaps the solution can just "inject" this template into the script as an argument
Ideally it would read the input CSV but this is not a hard requirement, if the solution requires me pasting the contents of the CSV file into the script as an argument, I'm OK with that, but not thrilled...
Ideally it would generate an actual SQL file (update_products.sql) for me, but if we're limited to console output thats OK to (just not preferred)
Any ideas how I might be able to accomplish this?
I'd probably start with
$: sed "s/ *= %ID%/ IN ( $(echo $(<ids.csv) ) )/" template.sql > update_products.sql
but if it's a lot of id's I'm not sure what your limits are, and I honestly don't remember whether that's an ANSI standard structure...
SO...
$: while IFS=, read -a ids
> do for id in ${ids[#]}
> do echo "UPDATE products SET quantity = 0 WHERE id = $id;"
> done
> done < ids.csv > update_products.sql
$: cat update_products.sql
UPDATE products SET quantity = 0 WHERE id = 29294848;
UPDATE products SET quantity = 0 WHERE id = 29294849;
UPDATE products SET quantity = 0 WHERE id = 29294850;
UPDATE products SET quantity = 0 WHERE id = 29294851;
UPDATE products SET quantity = 0 WHERE id = 29294853;
UPDATE products SET quantity = 0 WHERE id = 29294857;
UPDATE products SET quantity = 0 WHERE id = 29294858;
UPDATE products SET quantity = 0 WHERE id = 29294860;
UPDATE products SET quantity = 0 WHERE id = 29294861;
UPDATE products SET quantity = 0 WHERE id = 29294863;
UPDATE products SET quantity = 0 WHERE id = 29294887;
UPDATE products SET quantity = 0 WHERE id = 29294888;
UPDATE products SET quantity = 0 WHERE id = 29294889;
UPDATE products SET quantity = 0 WHERE id = 29294890;
UPDATE products SET quantity = 0 WHERE id = 29294891;
UPDATE products SET quantity = 0 WHERE id = 29294892;
UPDATE products SET quantity = 0 WHERE id = 29294895;
UPDATE products SET quantity = 0 WHERE id = 29294897;
UPDATE products SET quantity = 0 WHERE id = 29294898;
UPDATE products SET quantity = 0 WHERE id = 29294899;
UPDATE products SET quantity = 0 WHERE id = 29294901;
UPDATE products SET quantity = 0 WHERE id = 29294903;
UPDATE products SET quantity = 0 WHERE id = 29294912;
UPDATE products SET quantity = 0 WHERE id = 29294916;
Don't need to use %ID% - the ids.txt only needs to be prefixed with SQL like so, writing the output to product_updates.sql output file:
awk -F, '{printf "%s (%s)\n", "UPDATE products SET quantity = 0 WHERE id IN ", $0}' ids.txt > product_updates.sql
I propose to be safe rather than sorry.
May be deemed pedantic, but working with business database is serious matter.
So here it is based on #Paul Hodges's answer
#!/usr/bin/env bash
{
# Use the prepared statements `zeroproduct`
# to protect against SQL injections
printf 'PREPARE zeroproduct FROM '\''%s'\'';\n' \
'UPDATE products SET quantity = 0 WHERE id = ?'
# Work inside a transaction, so if something goes wrong,
# like the sql file is incomplete, it can be rolled-back.
printf 'START TRANSACTION;\n'
while IFS=, read -r -a ids; do
for id in "${ids[#]}"; do
# Set the value of the #id argument in SQL
# And execute the SQL statement with the #id argument
# that will replace the '?'
printf 'SET #id='\''%8d'\''; EXECUTE zeroproduct USING #id;\n' \
"$((id))" # Ensure id is an integer
done
done <ids.csv
# Now commit all these changes since we are finally here
printf 'COMMIT;\n'
# Deallocate the prepared statement once we are done
printf 'DEALLOCATE PREPARE zeroproduct;\n'
} >update_products.sql
# Good to have if this is transmitted remotely
sha512sum update_products.sql >update_products.sql.sha512sum
# can later check with:
sha512sum -c update_products.sql.sha512sum
From the provided sample csv, here is the content of update_products.sql:
PREPARE zeroproduct FROM 'UPDATE products SET quantity = 0 WHERE id = ?';
START TRANSACTION;
SET #id='29294848'; EXECUTE zeroproduct USING #id;
SET #id='29294849'; EXECUTE zeroproduct USING #id;
SET #id='29294850'; EXECUTE zeroproduct USING #id;
SET #id='29294851'; EXECUTE zeroproduct USING #id;
SET #id='29294853'; EXECUTE zeroproduct USING #id;
SET #id='29294857'; EXECUTE zeroproduct USING #id;
SET #id='29294858'; EXECUTE zeroproduct USING #id;
SET #id='29294860'; EXECUTE zeroproduct USING #id;
SET #id='29294861'; EXECUTE zeroproduct USING #id;
SET #id='29294863'; EXECUTE zeroproduct USING #id;
SET #id='29294887'; EXECUTE zeroproduct USING #id;
SET #id='29294888'; EXECUTE zeroproduct USING #id;
SET #id='29294889'; EXECUTE zeroproduct USING #id;
SET #id='29294890'; EXECUTE zeroproduct USING #id;
SET #id='29294891'; EXECUTE zeroproduct USING #id;
SET #id='29294892'; EXECUTE zeroproduct USING #id;
SET #id='29294895'; EXECUTE zeroproduct USING #id;
SET #id='29294897'; EXECUTE zeroproduct USING #id;
SET #id='29294898'; EXECUTE zeroproduct USING #id;
SET #id='29294899'; EXECUTE zeroproduct USING #id;
SET #id='29294901'; EXECUTE zeroproduct USING #id;
SET #id='29294903'; EXECUTE zeroproduct USING #id;
SET #id='29294912'; EXECUTE zeroproduct USING #id;
SET #id='29294916'; EXECUTE zeroproduct USING #id;
COMMIT;
DEALLOCATE PREPARE zeroproduct;
In addition to the answer by #suspectus which provides a nice use of printf to output each line wanted, a slightly more procedural use of awk incorporating a for loop over the fields would be:
awk -F, '{
for (i=1;i<=NF;i++)
print "UPDATE products SET quantity = 0 WHERE id = " $i ";"
}' file.csv
Where the single rule simply loops over each of the comma-separated fields using string-concatenation to form the desired output. In detail the awk command:
awk -F, sets the field-separator (FS) equal to a comma to split the input,
for (i=1;i<=NF;i++) simply loops over each field, and
print "UPDATE products SET quantity = 0 WHERE id = " $i ";" outputs the wanted text incorporating the field within using string-concatenation.
Example Use/Output
With your data in file.csv (presumed to be a single line, but it really doesn't matter) your output would be:
$ awk -F, '{
> for (i=1;i<=NF;i++)
> print "UPDATE products SET quantity = 0 WHERE id = " $i ";"
> }' file.csv
UPDATE products SET quantity = 0 WHERE id = 29294848;
UPDATE products SET quantity = 0 WHERE id = 29294849;
UPDATE products SET quantity = 0 WHERE id = 29294850;
UPDATE products SET quantity = 0 WHERE id = 29294851;
UPDATE products SET quantity = 0 WHERE id = 29294853;
UPDATE products SET quantity = 0 WHERE id = 29294857;
UPDATE products SET quantity = 0 WHERE id = 29294858;
UPDATE products SET quantity = 0 WHERE id = 29294860;
UPDATE products SET quantity = 0 WHERE id = 29294861;
UPDATE products SET quantity = 0 WHERE id = 29294863;
UPDATE products SET quantity = 0 WHERE id = 29294887;
UPDATE products SET quantity = 0 WHERE id = 29294888;
UPDATE products SET quantity = 0 WHERE id = 29294889;
UPDATE products SET quantity = 0 WHERE id = 29294890;
UPDATE products SET quantity = 0 WHERE id = 29294891;
UPDATE products SET quantity = 0 WHERE id = 29294892;
UPDATE products SET quantity = 0 WHERE id = 29294895;
UPDATE products SET quantity = 0 WHERE id = 29294897;
UPDATE products SET quantity = 0 WHERE id = 29294898;
UPDATE products SET quantity = 0 WHERE id = 29294899;
UPDATE products SET quantity = 0 WHERE id = 29294901;
UPDATE products SET quantity = 0 WHERE id = 29294903;
UPDATE products SET quantity = 0 WHERE id = 29294912;
UPDATE products SET quantity = 0 WHERE id = 29294916;
Look things over and let me know if you have further questions.

How to set a Condition for Movable Row

In Tabulator.js V 4.3 i can set MovableRows = true or false. I need to create a condition for deny or permit the moving of specific row.
Someone have a solution?
Have not tested but I suppose you could set rowHandle:
http://tabulator.info/docs/4.3/move#rows
Then do something like:
rowMouseEnter:function(e, row){if (Number(row.getCell("age").getValue()) < 20){row.getCell("handle").getColumn().hide()}else{row.getCell("handle").getColumn().show()}},

Set $objValidation/Dropdown range from variable

I am attempting to have phpexcel set the range for $objValidation based off a variable so not to have null values in my dropdown. This was my code
$objValidation->setFormula1('Index!$A$5:$A'.'count(Index!$A$5:$A$200');
which resulted in additional blank/null values in my dropbox making it bigger than need be. what I would like to do is something like this
$sql_temp = "SELECT `tempID`,`serialNUM` FROM `temp_sensor_specs` WHERE `statusTYPE`='SPARE'";
$result_temp = mysqli_query($link, $sql_temp);
$row_temp = mysqli_fetch_all($result_temp,MYSQLI_NUM);
$objPHPExcel->getActiveSheet()->fromArray($row_temp,null,'A5');
$count_temp = count($row_temp) + 4;
$objValidation = $objPHPExcel->getActiveSheet()->getCell('B4')->getDataValidation();
$objValidation->setType(PHPExcel_Cell_DataValidation::TYPE_LIST);
$objValidation->setErrorStyle(PHPExcel_Cell_DataValidation::STYLE_INFORMATION);
$objValidation->setAllowBlank(true);
$objValidation->setShowDropDown(true);
$objValidation->setErrorTitle('Input error');
$objValidation->setError('Value is not in list');
$objValidation->setFormula1('Index!$A$5:$A$count_temp');
So that didn't work I've also tried it in several variations as such
$objValidation->setFormula1('Index!$A$5:$A'.'$count_temp');
$objValidation->setFormula1('Index!$A$5:$A'.count($row_temp) + 4);
$objValidation->setFormula1('Index!$A$5:$A'$count_temp);
I really feel I've used syntax incorrectly, but can't figure out how. I've done similar range setting in loops for( $i=4; $i<=15; $i++ ){
$objValidation = $objPHPExcel->getActiveSheet()->getCell('B'.$i)->getDataValidation(); but also don't think this needs to be looped it should be a simple count and set that value as the count return +4 (as my dropdown starts on cell row 5)
thanks in advance
So the proper syntax ended up being `$objValidation->setFormula1('Index!$A$5:$A'."$count_temp");

Update ADO excel with two tables

I'm trying to change values of an excel workbook using Update but something is wrong i.e. y want to get the value from table B and put it in table a
my code is this, can you help me?
UPDATE [Data$]
SET A.[D ArtN] = B.[D ArtC]
FROM [Datos$] as A
INNER JOIN [Productos$] as B
ON A.[Art] = B.[ArtC]
UPDATE [Data$]
SET [Data$].[D ArtN] = [Productos$].[D ArtC]
WHERE [Data$].[Art] = [Productos$].[ArtC]
Is the correct format of an update statement. I'm not sure that this is the correct SQL syntax, as you did not specify if what you were using in Excel.
http://www.w3schools.com/sql/sql_update.asp

Resources