SQLite cannot update multiple tables at once - python-3.x

UPDATE X, Y
SET X.3="Updated String", Y.3="Updated String"
WHERE X.1 = Y.1
AND X.2 = Y.2;
The query above is working fine with MySQL. I'm having problems migrating it to SQLite as SQLite doesn't support multiple tables update at once (Subquerying might work, but I have no idea how to do it). I am trying to run this query using python's sqlite3 module.
Please consider X and Y as tables with columns 1,2,3.
Can anyone help me in this?
Thanks in advance

You can do it, but it requires trickiness. Make a view that joins the tables of interest (I assume that's a sensible thing to do) and set an INSTEAD OF UPDATE trigger on the view. Trigger programs can modify multiple different tables.
CREATE VIEW xy AS
SELECT X.3 AS x3, Y.3 AS y3, X.1 AS x1, X.2 AS x2
FROM X JOIN Y ON X.1 = Y.1 AND X.2 = Y.2;
CREATE TRIGGER xy_update
INSTEAD OF UPDATE ON xy
BEGIN
UPDATE X SET X.3 = NEW.x3 WHERE X.1 = NEW.x1 AND X.2 = NEW.x2;
UPDATE Y SET Y.3 = NEW.x3 WHERE Y.1 = NEW.x1 AND Y.2 = NEW.x2;
END;
Then you can do this:
UPDATE xy SET x3 = 'Updated String', y3 = 'Updated String';
-- No select required, but you can add one if you want
If you only need this for a short while, consider making xy and its trigger be TEMPORARY.

Multi table updates are not supported by SQLite.
It can be done only with 2 separate update statements:
UPDATE X
SET X.3 = 'Updated String'
WHERE EXISTS (SELECT 1 FROM Y WHERE X.1 = Y.1 AND X.2 = Y.2);
UPDATE Y
SET Y.3 = 'Updated String'
WHERE EXISTS (SELECT 1 FROM X WHERE X.1 = Y.1 AND X.2 = Y.2);

Related

Recordset empty issue

I have issue with filling up recordset.
I stored this query into txt file:
DROP TABLE IF EXISTS "temp_invoice_id_amount_1";
CREATE TEMPORARY TABLE "temp_invoice_id_amount_1" AS
SELECT
ROW_NUMBER() OVER() "RN",
c."ID" "CaseID",
p."ID" "PackageID",
trim(concat(d."LastName", ' ', d."FirstName")) "FullName",
c."ContragentCaseID",
i."ID" "InvoiceID",
i."AccountNum",
i."FromDate" "InvoiceFromDate",
i."ToDate" "InvoiceToDate",
i."InvoiceCurrency",
(coalesce(sum(td."Amount" * er."Value"), 0) * (-1)):: NUMERIC(12,2) "NumActualInvoiceAmount",
trim(replace(to_char((coalesce(sum(td."Amount" * er."Value"), 0) * (-1)):: NUMERIC(12,2), '99999990D00'),'.',',')) "ActualInvoiceAmount"
FROM "Package" p
JOIN "Case" c ON p."ID" = c."PackageID"
JOIN "Debtor" d ON d."ID" = c."DebtorID"
JOIN "Invoice" i ON c."ID" = i."CaseID" AND i."IsDeleted" = 0
LEFT JOIN "Transaction" t ON i."ID" = t."InvoiceID" AND t."IsDeleted" = 0 AND t."IsPayment" = 0
LEFT JOIN "TransactionDetails" td ON t."ID" = td."TransactionID"
LEFT JOIN "ExchangeRate" er ON
--t."PaymentDate" BETWEEN er."FromDate" AND er."ToDate" AND
er."SourceCurrency" = t."Currency" AND
er."DestinationCurrency" = i."InvoiceCurrency"
WHERE p."ID" in ($package)
AND i."AccountNum" not like 'OP%'
AND p."Inserted" + interval '1 minute' > i."Inserted"
group by c."ID", trim(concat(d."LastName", ' ', d."FirstName")), c."ContragentCaseID", i."FromDate", i."ToDate",
i."InvoiceCurrency", i."ID", p."ID";
CREATE UNIQUE INDEX "idx_temp_invoice_id_amount_1" ON temp_invoice_id_amount_1("InvoiceID");
DROP TABLE IF EXISTS "temp_case_id_amount_1";
CREATE TEMPORARY TABLE "temp_case_id_amount_1" AS
SELECT t1."CaseID",
trim(replace(to_char((coalesce(sum(t1."NumActualInvoiceAmount" * er_eur."Value"), 0)):: NUMERIC(12,2), '99999990D00'),'.',',')) "ActualCaseAmount_EUR",
trim(replace(to_char((coalesce(sum(t1."NumActualInvoiceAmount"), 0)):: NUMERIC(12,2), '99999990D00'),'.',',')) "ActualCaseAmount_HRK"
FROM temp_invoice_id_amount_1 t1
LEFT JOIN "ExchangeRate" er_eur ON
current_date BETWEEN er_eur."FromDate" AND er_eur."ToDate" AND
er_eur."SourceCurrency" = t1."InvoiceCurrency" AND
er_eur."DestinationCurrency" = 'EUR'
LEFT JOIN "ExchangeRate" er_hrk ON
current_date BETWEEN er_hrk."FromDate" AND er_hrk."ToDate" AND
er_hrk."SourceCurrency" = t1."InvoiceCurrency" AND
er_hrk."DestinationCurrency" = 'HRK'
GROUP BY t1."CaseID";
CREATE UNIQUE INDEX "idx_temp_case_id_amount_1" ON temp_case_id_amount_1("CaseID");
SELECT ti1."RN",
ti1."CaseID",
--ti1."PackageID",
ti1."FullName",
'ZIPPY',
'CITTY',
'STREETY',
ti1."ContragentCaseID",
--ti1."InvoiceID",
-- ti1."AccountNum",
ti1."InvoiceFromDate",
ti1."InvoiceToDate",
ti1."InvoiceCurrency",
ti1."ActualInvoiceAmount",
'0',
--tc1."ActualCaseAmount_EUR",
tc1."ActualCaseAmount_HRK",
'0'
FROM temp_invoice_id_amount_1 ti1
JOIN "temp_case_id_amount_1" tc1 ON ti1."CaseID" = tc1."CaseID";
Then i used this part to read from txt file:
Dim strSQL2 As String
fileSpec = "\\192.168.0.7\...\Reports\confirmation.txt"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTS = objFSO.OpenTextFile(fileSpec, ForReading)
strSQL2 = objTS.ReadAll
strSQL2 = Replace(strSQL2, "$package", package)
objTS.Close
And this part for executing the query:
cmd.CommandType = ADODB.CommandTypeEnum.adCmdText
cmd.ActiveConnection = Conn
cmd.CommandText = strSQL
cmd2.CommandType = ADODB.CommandTypeEnum.adCmdText
cmd2.ActiveConnection = Conn
cmd2.CommandText = strSQL2
Set rs = New ADODB.Recordset
Set rs = cmd.Execute
Set rs2 = New ADODB.Recordset
Set rs2 = cmd2.Execute
But for some reason recordset rs2 is totally empty while rs1 is normally filled with data.
Does anyone knows what could be reason why recordset rs2 is empty?
I don't know for sure, but I suspect the issue is you are executing everything at once. It's likely doing everything but not returning the results the way you expect.
I think what you may want to do is execute each code block in sequence rather than all at once.
Something like this:
Dim rs2 as ADODB.Recordset
For Each codeBlock In Split(strSQL2, ";")
cmd2.CommandText = codeBlock
rs2 = cmd2.Execute
Next codeBlock
You can also put a breakpoint on each "execute" to check the results at each step.
You'll probably also need to omit the final semicolon so it doesn't try to execute blank (or otherwise handle that the command text has to contain some non-whitespace).
Out of curiosity, why the temp tables? Why not simply run the query? Have you considered functions/views?
I didn't find exact solution but workaround solution.
I splitted my query into 2 separate txt files.
First file contains part where i am dropping and creating temp tables,
and second file contains only this:
SELECT ti1."RN",
ti1."CaseID",
--ti1."PackageID",
ti1."FullName",
'ZIPPY',
'CITTY',
'STREETY',
ti1."ContragentCaseID",
--ti1."InvoiceID",
-- ti1."AccountNum",
ti1."InvoiceFromDate",
ti1."InvoiceToDate",
ti1."InvoiceCurrency",
ti1."ActualInvoiceAmount",
'0',
--tc1."ActualCaseAmount_EUR",
tc1."ActualCaseAmount_HRK",
'0'
FROM temp_invoice_id_amount_1 ti1
JOIN "temp_case_id_amount_1" tc1 ON ti1."CaseID" = tc1."CaseID";
Then i executed these 2 files separately.

Power query recursive function: add more steps after the recursive step

Background:
I have posted a question regarding a custom function in Power Query that I found in a blog by Chris Webb which I have already got an answer to.But now I have another question related to the same custom function.
One of the amazing steps in that custom function is the recursive step at the end named "OutputTable" which calls itself using a if statement, basically making it a loop. Below is the step:
OutputTable = if NextColumnNumber>(Table.ColumnCount(ExpandedTable)-1) then ExpandedTable else ExpandAll(ExpandedTable, NextColumnNumber)
Question:
Now what I would like to do after this step is to be able to add more transformation on the OutputTable.
For Example, I would like to add a column with just "A" in all the rows. The syntax to do that would be AddNewColumn = Table.AddColumn(OutputTable, "Test", each "A"). But when I do this this gives me an error saying that the column "Test" already exists. But i'm sure that there is no other column with name "Test". Even if I try changing the name of the column to anything else, I get the same error.
Note: Although the actual step I want to add is not AddColumn, I think I can figure out that part If I get a solution for this.
SourceCode:
let
Source = (TableToExpand as table, optional ColumnNumber as number) =>
let
ActualColumnNumber = if (ColumnNumber=null) then 0 else ColumnNumber,
ColumnName = Table.ColumnNames(TableToExpand){ActualColumnNumber},
ColumnContents = Table.Column(TableToExpand, ColumnName),
ColumnsToExpand = List.Select(List.Distinct(List.Combine(List.Transform(ColumnContents, each if _ is table then Table.ColumnNames(_) else {}))), each (_ = "view" or _ = "viewfolder" or _ = "Attribute:name")),
NewColumnNames = List.Transform(ColumnsToExpand, each ColumnName & "." & _),
CanExpandCurrentColumn = List.Count(ColumnsToExpand)>0,
ExpandedTable = if CanExpandCurrentColumn then Table.ExpandTableColumn(TableToExpand, ColumnName, ColumnsToExpand, NewColumnNames) else TableToExpand,
NextColumnNumber = if CanExpandCurrentColumn then ActualColumnNumber else ActualColumnNumber+1,
OutputTable = if NextColumnNumber>(Table.ColumnCount(ExpandedTable)-1) then ExpandedTable else ExpandAll(ExpandedTable, NextColumnNumber)
in
OutputTable
in
Source
I'm guessing it's throwing the error due to the recursive nature of the function calling itself and trying to apply the new column twice, once in the innermost loop and once in the outermost loop.
Let's say we have a table with two columns Col1 and Col2 that need to be expanded. If you add the new column after the OutputTable step, you'll get:
Start: Col0, Col1, Col2
OutputTable(1): Col0, Col1.a, Col1.b, Col2
OutputTable(2): Col0, Col1.a, Col1.b, Col2.x, Col2.y, Col2.z, Test
AddNewColumn: Col0, Col1.a, Col1.b, Col2.x, Col2.y, Col2.z, Test, Test
Here are a couple of approaches to try:
1. Only try to add the column when recursion is finished.
I think you can do this by changing your OutputTable line as follows:
OutputTable = if NextColumnNumber>(Table.ColumnCount(ExpandedTable)-1)
then Table.AddColumn(ExpandedTable, "Test", each "A")
else ExpandAll(ExpandedTable, NextColumnNumber)
2. Check if the column exists before trying to add it.
AddNewColumn = if Table.HasColumns(OutputTable, "Test")
then OutputTable
else Table.AddColumn(OutputTable, "Test", each "A")

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

In an Excel chart: how to "copy" chart line format from one series to another using VBA?

For some x and y such that SeriesCollection(x) exists and SeriesCollection(y) exists, I am trying to do the following:
ActiveChart.SeriesCollection(x).Format.Line = ActiveChart.SeriesCollection(y).Format.Line
But, that gives me an error: "object doesn't support this property or method". How can I copy the line format of one series from a chart, to another series in the chart?
You have to iterate through each property of .Format.Line
(It's confusing to use X and Y as variables indicating series, since X and Y conventionally refer to data of those series.)
Set srsA = ActiveChart.SeriesCollection(A)
Set srsB = ActiveChart.SeriesCollection(B)
srsA.Format.Line.ForeColor = srsB.Format.Line.ForeColor
srsA.Format.Line.Weight = srsB.Format.Line.Weight
etc.

Using legend in MATLAB

I have a plot in a for loop and I need to use the legend command to label them. I need to create a array of strings to use the same. For some reason it just doesn't seem to work. Can somebody help. I am pasting the code below.
for i = 1:len
for j = 1:C{i,1}/n
cc = hsv(12);
semilogx(w/pi,Same_psd{i,1}(:,j+1),'color',cc(j+1,:))
str = num2str(Same_mean{i,j+1});
srt_array = [str_array; str];
legend(str_array);
end
end
Try this:
legend_labels = cell(10,1);
for i = 1:10
h(i) = plot(randn(10,1));
hold all
legend_labels{i} = sprintf('This is label #%i', i);
end;
legend(h,legend_labels{:})
Try using the DisplayName property. Has the nice side effect that you can guaranty the legend is in sync with your lines.
eg:
clf
hold on
for i = 1:10
col = rand(3,1);
semilogx(1:10,rand(10,1),'DisplayName',sprintf('This is curve %i',i),...
'color',col)
end
legend('Location','best')

Resources