dblink_build_sql_delete . I need to be able to delete the data with <= condition - postgresql

SELECT xyz.*
FROM PUBLIC.DBLINK ('dbname=LiveDB port=5432 host=127.0.0.1 user=postgres
password=root','SELECT dblink_build_sql_delete(''"folderstatus"'', ''1'', 1,
''{"1"}'')')
as xyz (id int);
ERROR: invalid input syntax for integer: "DELETE FROM folderstatuslu WHERE
id = '1'"
I'm unable to delete the record here. I also need to know how to add a "<=" condition and also need to pass a parameter.
My code will be like this, I'll be selecting the max(colum_value) into a variable and pass it to the above query and should be able to delete like below.
DELETE FROM folderstatuslu WHERE id <= '1' --> (in the place of 1, I will
pass a variable.)
Appreciate your help.

why not just dblink and format?..
t=# create table so43 (i int);
CREATE TABLE
t=# insert into so43 select 1;
INSERT 0 1
t=# select * from dblink('dbname = t',format('delete from so43 where i <= %s',1)) as row(result text);
result
----------
DELETE 1
(1 row)

Related

Postgres 10: do rows automatically move between partitions?

Assuming I have a parent table with child partitions that are created based on the value of a field.
If the value of that field changes, is there a way to have Postgres automatically move the row into the appropriate partition?
For example:
create table my_table(name text)
partition by list (left(name, 1));
create table my_table_a
partition of my_table
for values in ('a');
create table my_table_b
partition of my_table
for values in ('b');
In this case, if I change the value of name in a row from aaa to bbb, how can I get it to automatically move that row into my_table_b.
When I tried to do that, (i.e. update my_table set name = 'bbb' where name = 'aaa';), I get the following error:
ERROR: new row for relation "my_table_a" violates partition constraint
https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=f0e44751d7175fa3394da2c8f85e3ceb3cdbfe63
it doesn't handle updates that cross partition boundaries.
thus you need to create one yourself... here's your set:
t=# insert into my_table select 'abc';
INSERT 0 1
t=# insert into my_table select 'bcd';
INSERT 0 1
t=# select tableoid::regclass,* from my_table;
tableoid | name
------------+------
my_table_a | abc
my_table_b | bcd
(2 rows)
here's rule and fn():
t=# create or replace function puf(_j json,_o text) returns void as $$
begin
raise info '%',': '||left(_j->>'name',1);
execute format('insert into %I select * from json_populate_record(null::my_table, %L)','my_table_'||left(_j->>'name',1), _j);
execute format('delete from %I where name = %L','my_table_'||left(_o,1), _o);
end;
$$language plpgsql;
CREATE FUNCTION
t=# create rule psr AS ON update to my_table do instead select puf(row_to_json(n),OLD.name) from (select NEW.*) n;
CREATE RULE
here's update:
t=# update my_table set name = 'bbb' where name = 'abc';
INFO: : b
puf
-----
(1 row)
UPDATE 0
checking result:
t=# select tableoid::regclass,* from my_table;
tableoid | name
------------+------
my_table_b | bcd
my_table_b | bbb
(2 rows)
once again:
t=# update my_table set name = 'a1' where name = 'bcd';
INFO: : a
puf
-----
(1 row)
UPDATE 0
t=# select tableoid::regclass,* from my_table;
tableoid | name
------------+------
my_table_a | a1
my_table_b | bbb
(2 rows)
Of course using json to pass NEW record looks ugly. And it is ugly indeed. But I did not have time to study the new PARTITION feature of 10, so don't know the elegant way to do this task. Hopefully I could give the generic idea of how you can possible solve the problem and you will produce a better neat code.
update
its probablygood idea to limit such rule to ON update to my_table where left(NEW.name,1) <> left(OLD.name,1) do instead, to release the heavy manipulations need

IF Exists doesn't seem to work for a Table Drop if already exists

Was getting this error each and every time tried to execute a DROP Table if exists
Step 1: Created a Table
CREATE TABLE Work_Tables.dbo.Drop_Table_Test (RowID INT IDENTITY(1,1), Data VARCHAR(50))
INSERT INTO Work_Tables.dbo.Drop_Table_Test
SELECT 'Test' UNION
SELECT 'Test1' UNION
SELECT 'Test2' UNION
SELECT 'Test3'
Step 2: Wrote a IF Exists block to check if the Table exists.
IF EXISTS (SELECT 1 FROM Work_Tables.dbo.SysObjects WHERE NAME LIKE 'Drop_Table_Test' AND XType = 'U')
BEGIN
PRINT 'IN'
DROP TABLE Work_Tables.dbo.Drop_Table_Test
END
CREATE TABLE Work_Tables.dbo.Drop_Table_Test (RowID INT IDENTITY(1,1), Data VARCHAR(50), NAME VARCHAR(20), PreCheck INT)
INSERT INTO Work_Tables.dbo.Drop_Table_Test (Data, Name, PreCheck)
SELECT 'Test','SRK',1 UNION
SELECT 'Test1','Daya',2 UNION
SELECT 'Test2','Dinesh',3 UNION
SELECT 'Test3','Suresh',4
On running the Step 2 Code its obvious the Table has to be Dropped and recreated with the same name but it didn't even enter the Begin End block.
I feel that its because have added few more columns in the second try, but still not clear why it should have problems as we are to DROP the table.
You can not drop and create the same table in the same batch in SQL Server.
Break your code up into separate batches so the table can be dropped before you try and recreate it. Add GO after END in your BEGIN / END statement.
IF EXISTS (SELECT 1 FROM Work_Tables.dbo.SysObjects WHERE NAME LIKE 'Drop_Table_Test' AND XType = 'U')
BEGIN
PRINT 'IN'
DROP TABLE Work_Tables.dbo.Drop_Table_Test
END
GO --Add this...
....
Straight from Microsoft's Documentation:
DROP TABLE and CREATE TABLE should not be executed on the same table in the same batch. Otherwise an unexpected error may occur.
You can try to use this syntax:
IF OBJECT_ID('dbo.Drop_Table_Test', 'U') IS NOT NULL
DROP TABLE dbo.Drop_Table_Test;
IF EXISTS will drop the table only when your table Drop_Table_Test does not contain any row. In case if it contains the data then it will not drop the table.

How does postgres db_link_build_sql_insert work?

I can't seem to figure out how this function is supposed to work for pushing data across from one table in your local database to another on a separate database. I have looked at the documentation and still don't understand the example given. I am working with a postgres 9.2 which makes it possible to use dblink.
Here is some example code where I am creating a test database and pushing values from my local table to the table on the test database. Can someone please fill in the missing part of the dblink_build_sql_insert function?
--drop database if exists testdb;
--create database testdb;
drop table if exists t;
create table t ( a integer, b text);
insert into t values (1,'10'), (2,'10'), (3,'30'), (4,'30');
create extension if not exists dblink;
select dblink_connect('dbname=testdb');
select dblink('drop table if exists t;');
select dblink('create table t ( a integer, b text);');
select dblink_build_sql_insert('t', ????);
select * from dblink('select * from t;') as (a integer, b text);
from docs:
Synopsis
dblink_build_sql_insert(text relname,
int2vector primary_key_attnums,
integer num_primary_key_atts,
text[] src_pk_att_vals_array,
text[] tgt_pk_att_vals_array) returns text
You don't have PK specified, so I assume it is on (a), which automatically means, that primary_key_attnums = 1(PK on first column) and num_primary_key_atts=1 (one column PK). Two rest values made same to prepare statement ro "replicate" row with a=1 as is:
b=# select dblink_build_sql_insert('t',
'1'::int2vector,
1::int2, -- num of pkey values
'{1}'::text[], -- old pkey
'{1}'::text[] -- new pkey
)
;
dblink_build_sql_insert
-------------------------------------
INSERT INTO t(a,b) VALUES('1','10')
(1 row)
b=# select dblink($$INSERT INTO t(a,b) VALUES('1','10')$$);
dblink
----------------
("INSERT 0 1")
(1 row)
b=# select * from dblink('select * from t;') as (a integer, b text);
a | b
---+----
1 | 10
(1 row)
b=# select dblink_disconnect();
dblink_disconnect
-------------------
OK
(1 row)

Using return value from DELETE for UPDATE in Postgres

I need to update a table using a value deleted from another table. The situation is a comment vote scorekeeper similar to the one on SO. I'm using python to work the postgres, but that shouldn't make a difference.
query="""
UPDATE comment SET score=score-(DELETE FROM history
WHERE commentId=%(commentId)s AND
userIdentity=%(userIdentity)s RETURNING vote)
WHERE commentId=%(commentId)s;
"""
cursor.execute(query, data)
The error arises at (DELETE FROM; a syntax error arises. I can replace the DELETE statement with a SELECT statement and it will work, is there something I am missing here? I want to use the returning value in an update. Is this possible? Anything helps.
Relevent schema:
CREATE TABLE history (
commentId bigint,
vote int,
userIdentity varchar(256),
);
CREATE TABLE comment (
id bigint,
score bigint,
);
history.vote is normally 1 or -1.
PostgreSQL doesn't allow mix UPDATE and DELETE statements as subquery.
You can use a little bit different strategy - updateable CTE
postgres=# WITH t1 AS (DELETE FROM foo RETURNING *),
t2 AS (INSERT INTO deleted
SELECT * FROM t1 RETURNING *)
SELECT max(a) FROM t2;
so
postgres=# CREATE TABLE comment(id int, score int);
CREATE TABLE
postgres=# CREATE TABLE history(id int, comment_id int, vote int);
CREATE TABLE
postgres=# INSERT INTO comment values(1,10);
INSERT 0 1
postgres=# INSERT INTO comment values(2,20);
INSERT 0 1
postgres=# INSERT INTO history values(1,1,5);
INSERT 0 1
postgres=# WITH t1 AS (DELETE FROM history
WHERE id=1
RETURNING comment_id, vote)
UPDATE comment SET score=score-t1.vote
FROM t1
WHERE t1.comment_id=comment.id;
UPDATE 1
postgres=# select * from comment;
id | score
----+-------
2 | 20
1 | 5
(2 rows)
Attention: It require 9.1 or newer

What's wrong with this tsql?

When executing the following script, I get the error:
Msg 207, Level 16, State 1, Line 15 Invalid column name 'b'.
Anyone can explain it please? Thanks.
DROP TABLE ttt;
CREATE TABLE ttt(a nvarchar)
IF NOT EXISTS ( SELECT *
FROM sys.columns
WHERE object_id = OBJECT_ID('dbo.ttt')
AND name = 'b' )
AND EXISTS ( SELECT *
FROM sys.columns
WHERE object_id = OBJECT_ID('dbo.ttt')
AND name = 'a' )
BEGIN
ALTER TABLE [dbo].ttt ADD b NVARCHAR
UPDATE [dbo].ttt
SET b = a
ALTER TABLE [dbo].ttt DROP COLUMN a
END
It's trying to compile all of these statements before it executes the 1st:
ALTER TABLE [dbo].ttt ADD b NVARCHAR
UPDATE [dbo].ttt
SET b = a
ALTER TABLE [dbo].ttt DROP COLUMN a
(In fact, it tries to compile the entire batch, not just these statements, but the point still stands - at the point it's trying to compile the UPDATE, the column does not exist)
When it's trying to compile the UPDATE statement, it consults the table metadata and correctly finds that the column doesn't exist.
Try EXECing the update statement.
EXEC('UPDATE [dbo].ttt
SET b = a');
And also, what Oded says about you probably wanting to specify a size for the column (otherwise, it defaults to the most pointless datatype ever - an nvarchar(1))
This script definitely runs without errors:
CREATE TABLE ttt(a nvarchar)
IF NOT EXISTS ( SELECT *
FROM sys.columns
WHERE object_id = OBJECT_ID('dbo.ttt')
AND name = 'b' )
AND EXISTS ( SELECT *
FROM sys.columns
WHERE object_id = OBJECT_ID('dbo.ttt')
AND name = 'a' )
BEGIN
ALTER TABLE [dbo].ttt ADD b NVARCHAR
EXEC('UPDATE [dbo].ttt
SET b = a');
ALTER TABLE [dbo].ttt DROP COLUMN a
END
If you put the code in a stored procedure it should work. Just make sure the table exists with both columns a and column b when you create the procedure. Then after the procedure has been created you can drop the table and test it.