When does this query gets generated? - oracle12c

When does this query get generated by the system?
DELETE FROM LBACSYS.LBAC$POLT WHERE TBL_NAME = UPPER(:B2 ) AND OWNER = UPPER(:B1 )
I googled it and found out that it is related to label security and nothing more.

Deletes the entry from the table if both the table name and owner name match.

It deletes all rows from LBAC$POLT table owned by LBACSYS whose
column tbl_name is equal to value passed through the b2 parameter (or a bind variable), converted to upper case
column owner is eqal to value passed through b1, converted to upper case
For example:
SQL> select * from lbac$polt;
OWNER TABLE_NAME
----- ----------
SCOTT EMP
SCOTT DEPT
(this is a SQL*Plus client which uses substitution variables, e.g. &b2; your code uses bind variables; at the end, the result is just the same):
SQL> delete from lbac$polt where table_name = upper('&b2') and owner = upper('&b1');
Enter value for b2: emp
Enter value for b1: scott
old 1: delete from lbac$polt where table_name = upper('&b2') and owner = upper('&b1')
new 1: delete from lbac$polt where table_name = upper('emp') and owner = upper('scott')
1 row deleted.
Result:
SQL> select * from lbac$polt;
OWNER TABLE_NAME
----- ----------
SCOTT DEPT
SQL>

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

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

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)

Using a CASE Expression in the Default Value

I am creating a script for my dba to run. In development I have added a new column to an existing table. When I run the following script I have separated the ALTER and UPDATE on my table. I was trying to combine the statements into one. Any suggestions? Not sure if this is possible or I am on the right track. Thanks in advance!
Current Script that is working fine:
if not exists(select * from sys.columns where Name = N'NewColumn' and
Object_ID = Object_ID(N'TableA'))
begin
ALTER TABLE dbo.TableA
ADD NewColumn BIT NULL
DEFAULT 0
end
if exists(select * from sys.columns where Name = N'NewColumn' and Object_ID = Object_ID(N'TableA'))
begin
UPDATE dbo.TableA
SET Newcolumn = CASE WHEN CodeID IN ('A','B') THEN 1 END
WHERE CodeID IN ('A','B')
end
Trying to combine the ALTER and UPDATE into one:
if not exists(select * from sys.columns where Name = N'NewColumn' and Object_ID = Object_ID(N'TableA'))
begin
ALTER TABLE dbo.TableA
ADD NewColumn BIT NULL
DEFAULT case CodeID
WHEN 'A' THEN 1
WHEN 'B' THEN 1
end
I get the following error:
The name "CodeID" is not permitted in this context. Valid expressions are constants, constant expressions, and (in some contexts) variables. Column names are not permitted.
I haven't actually tested this, but I noticed you used different syntax for the CASE statement in the working script and the non-working script. Try this:
if not exists(select * from sys.columns where Name = N'NewColumn' and Object_ID = Object_ID(N'TableA'))
begin
ALTER TABLE dbo.TableA
ADD NewColumn BIT NULL
DEFAULT case WHEN CodeID = 'A' THEN 1 ELSE 0 END
end
But it would not surprise me if you can't reference another column in the default for a column. For example, what happens when you insert a new record without specifying a value for NewColumn? At insert time, CodeID doesn't have a value because the row doesn't exist yet.
Ok, so i did some more digging around. The following solves my problem:
if not exists(select * from sys.columns where Name = N'NewColumn' and
Object_ID = Object_ID(N'TableA'))
begin
ALTER TABLE dbo.TableA
ADD NewColumn BIT NULL
DEFAULT 0 with Values
end
if exists(select * from sys.columns where Name = N'NewColumn' and Object_ID = Object_ID(N'TableA'))
begin
UPDATE dbo.TableA
SET Newcolumn = 1 WHERE CodeID IN ('A','B')
end
I was over complicating things. In order to combine the update I would have to try and add a trigger. This works for what I need to do. Thanks.

PostgreSQL Type Method

How do I create type methods in PostgreSQL?
Lets take the following type for example:
create type Employee as (
name varchar(20),
salary integer)
How do I do this?
create method giveraise (percent integer) for Employee
begin
set self.salary = self.salary + (self.salary * percent) / 100;
end
You have been told in the comments, that Postgres doesn't have type methods.
However, Postgres supports attribute notation for the execution of functions with a single parameter. This looks almost exactly like a method for the type. Consider this simple example:
CREATE OR REPLACE FUNCTION raise10(numeric)
RETURNS numeric LANGUAGE sql AS 'SELECT $1 * 1.1';
Call:
SELECT (100).raise10;
Result:
raise10
---------
110.0
A major limitation is that this only works for a single parameter. No way to pass in additional parameters like a percentage for a variable raise.
Works for composite types just as well. More about "computed fields" in this related answer:
Store common query as column?
To take this one step further, one can even call an UPDATE on the row and persist the change:
CREATE TABLE employee (
name text PRIMARY KEY,
salary numeric);
INSERT INTO employee VALUES
('foo', 100)
,('bar', 200);
CREATE OR REPLACE FUNCTION giveraise10(employee)
RETURNS numeric AS
$func$
UPDATE employee
SET salary = salary * 1.1 -- constant raise of 10%
WHERE name = ($1).name
RETURNING salary;
$func$ LANGUAGE sql;
Call:
SELECT *, e.giveraise10 FROM employee e;
Result:
name | salary | giveraise10
------+--------+-------------
foo | 100 | 110.0
bar | 200 | 220.0
->sqlfiddle
The SELECT displays the pre-UPDATE value for salary, but the field has actually been updated!
SELECT *, e.giveraise10 FROM employee e;
name | salary
------+--------
foo | 110.0
bar | 220.0
Whether it's wise to use such trickery is for you to decide. There are more efficient and transparent ways to update a table.

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.