How to avoid multiple insert in PostgreSQL - postgresql

In my query im using for loop. Each and every time when for loop is executed, at the end some values has to be inserted into table. This is time consuming because for loop has many records. Due to this each and every time when for loop is executed, insertion is happening. Is there any other way to perform insertion at the end after the for loop is executed.
For i in 1..10000 loop ....
--coding
insert into datas.tb values(j,predictednode); -- j and predictednode are variables which will change for every loop
End loop;
Instead of inserting each and every time i want the insertion should happen at the end.

If you show how the variables are calculated it could be possible to build something like this:
insert into datas.tb
select
calculate_j_here,
calculate_predicted_node_here
from generate_series(1, 10000)

One possible solution is to build a large VALUES String. In Java, something like
StringBuffer buf = new StringBuffer(100000); // big enough?
for ( int i=1; i<=10000; ++i ) {
buf.append("(")
.append(j)
.append(",")
.append(predicted_node)
.append("),"); // whatever j and predict_node are
}
buf.setCharAt(buf.length()-1, ' '); // kill last comma
String query = "INSERT INTO datas.tb VALUES " + buf.toString() + ";"
// send query to DB, just once
The fact j and predict_node appear to be constant has me a little worried, though. Why are you putting a constant in 100000 times?
Another approach is to do the predicting in a Postgres procedural language, and have the DB itself calculate the value on insert.

Related

PostgreSQL: How do you set a "counter" variable as an array index in a while loop statement?

I am trying to implement a while loop that will create new table rows for each element in an array.
In the code below, prc_knw is a user-input expression that is structured as an array. I want to take each of the elements in prc_knw and separate them into new rows in my table processknowledgeentry where each row has the same prc_id taken from another table. Each time the statement loops, I want it to move to the next prc_knw array element, and I want the variable counter to indicate the index.
do $$
declare
counter integer := 1;
begin
while counter <= (select array_length(prc_knw,1)) loop
INSERT INTO processknowledgeentry (prc_id,knw_id, pke_delete_ind)
VALUES ((SELECT prc_id FROM process
WHERE prc_id = (SELECT MAX(p.prc_id) FROM process AS p)),prc_knw[counter], False);
counter := counter + 1;
end loop;
end$$;
I'm stuck on how to format prc_knw[counter]. The error I get is: SyntaxError: syntax error at or near "[" LINE 14: ...ECT MAX(p.prc_id) FROM process AS p)),ARRAY[1,2,3][counter],...
I've tried formatting it like prc_knw['%',counter], and the error I receive is: IndexError: list index out of range (because I'm building this app in Python Dash and it's connected to a database in pgAdmin 4).
Hope you can help, thank you! Also feel free to let me know if there is a better approach to this.

ROWCOUNT field in SYSTABLES table not updated after rows have been deleted

I use the ROWCOUNT field in SYSTABLES to get fast the rowcount of all my tables from a .NET App using Oledb (i don't want to use a query to get it becasue it takes too much time on big tables).
The problem is: after deleting rows from the table, that ROWCOUNT number in SYSTABLES is not updated. I tested some commands and even found that running ROWCOUNT TABLENAME in SqlTalk works and is very fast, but if i try to call that as a query from .NET using OLEDB it's returning nothing, sample code:
using (var connection = ConnectionFactory.CreateConnection(NombreBaseModelo))
{
using (OleDbCommand cmd = connection.CreateCommand())
{
foreach (Tabla ot in LstTables)
{
cmd.CommandType = CommandType.Text;
cmd.CommandTimeout = 5000;
cmd.CommandText = "ROWCOUNT " + ot.NAME;
var sRet = cmd.ExecuteScalar();
ot.ROWCOUNT = int.Parse(sRet);
}
}
}
Is there any way to tell SqlBase to update Rowcount for each table in systables?
Or as alternative, is there any way to make this code work?
Thanks!
The systables.rowcount only gets updated when an update statistics is done, so it's not guaranteed to be accurate, until you execute 'Update Statistics on table ' + ot.NAME;
Then it is .
Probably not what you want when quickly counting rows.
Does your 'ot.NAME' variable have a table owner included ? usually its 'SYSADM.'
Have you checked the value returned in 'sRet' , as maybe its 'int.Parse(sRet)' that is failing.
Otherwise create an index on the PK and execute a COUNT(*) . Should be as fast as ROWCOUNT anyway if the index is being used .
Alternatively, write a SQLBase function or stored proc that just executes the ROWCOUNT command natively and returns the correct count ( as per SQLTalk ), and call that from your , Net app

increment sequence in PostgreSQL stored procedure

How to auto increment sequence number once for every run of a stored procedure and how to use it in the where condition of an update statement?
I already assigned a sequence number to the next value in each run, but I'm not able to use it in the where condition.
CREATE OR REPLACE FUNCTION ops.mon_connect_easy()
RETURNS void
LANGUAGE plpgsql
AS $function$
declare
_inserted_rows bigint = 0;
sql_run bigint = 0;
--assigning the sequence number to the variable
select nextval('ops.mon_connecteasy_seq') into run_seq_num;
-- use for selection iteration_id. this is hwere I'm getting stuck
update t_contract c
set end_date = ce.correct_end_date, status='Active',
orig_end_date =ce.correct_end_date
from ops.t_mon_ConnectEasy ce
where c.contract_id = ce.contract_id
and run_seq_num = ??;
nextval() advances the sequence automatically before returning the resulting value. You don't need anything extra. Just use the function in your query directly:
update t_contract c
set end_date = ce.correct_end_date
, status = 'Active'
, orig_end_date = ce.correct_end_date
from ops.t_mon_ConnectEasy ce
where c.contract_id = ce.contract_id
and iteration_id = nextval('ops.mon_connecteasy_seq');
Be aware that concurrent transactions also might advance the sequence, creating virtual gaps in the sequential numbers.
And I have a nagging suspicion that this might not be the best way to achieve your undisclosed goals.

Using a value from a for loop in a function

Hi i am trying to create a function which loops from 1 to 12 and then use that loop value to calculate a date here is my code so far for the loop which is where the problem is.
FOR i IN 1..12 LOOP
r.duedate := alert_start_period + interval 'i month';
RAISE NOTICE 'Month % gives date of %', i, r.duedate;
END LOOP;
I know the problem is how i am referencing the value i. How do i correctly reference i from the loop so the interval is correct please.
The Error being thrown is
ERROR: invalid input syntax for type interval: "i month"
You can't substitute a var into a string like that. Without using dynamic SQL, the cleanest way is a multiplier:
r.duedate := alert_start_period + i * INTERVAL '1' MONTH;
However, this whole idea is ugly. The loop is unnecessary. Use:
generate_series(alert_start_period, alert_start_period + INTERVAL '12' MONTH, INTERVAL '1' MONTH)
to generate the intervals. If you must, you can loop over that, but I generally find that everything not requiring exception handling is better done as normal set operations rather than pl/pgsql loops.

TSQL: Declare variables with a counter in the name

How do I create/declare variables with a counter in the name on a MS SQL Server?
I have a "for-like" loop with CURSOR and
WHILE ##FETCH_STATUS = 0
BUT: the number of those values is changing continuously. So i want to write every value in an own variable. My goal is to get var-names like : #var1, next loop #var2, next #var3 etc.
Well
SET #counter = (#counter + 1)
is not THAT difficult, but how do I add the value(!) of #counter to the name(!) of #var?
THX a LOT!
I think you should create a temp table to store these variables. For example:
DECLARE #ValTable TABLE
(
ID int,
Val int, -- or any type you need
)
Now insert a new value:
SET #counter = (#counter + 1);
INSERT INTO #ValTable VALUES (#counter, <VALUE>);
To get this value [i] use simple select:
SELECT Val FROM #ValTable where ID=<Number of value here>;
I don't really understand what you are trying to achieve, but a way to do it would be to build the query string within your for loop as you want it to be than execute it to get the result formatted as you want it.