How to write a WHERE clause for NULL value in ARRAY type column? - sql

I created a table which contains a column of string ARRAY type as:
CREATE TABLE test
(
id integer NOT NULL,
list text[] COLLATE pg_catalog."default",
CONSTRAINT test_pkey PRIMARY KEY (id)
)
I then added rows which contain various values for that array, including an empty array and missing data (null):
insert into test (id, list) values (1, array['one', 'two', 'three']);
insert into test (id, list) values (2, array['four']);
insert into test (id, list) values (3, array['']);
insert into test (id, list) values (4, array[]::text[]); // empty array
insert into test (id, list) values (5, null); // missing value
pgAdmin shows table like this:
I am trying to get a row which contains a null value ([null]) in the list column but:
select * from test where list = null;
...returns no rows and:
select * from test where list = '{}';
...returns row with id = 4.
How to write WHERE clause which would target NULL value for column of ARRAY type?

demo:db<>fiddle
... WHERE list IS NULL

select * from test where list IS null;

Like this:
select * from test where list IS NULL;

Related

Not able to insert a row in a table which has auto incremented primary key

I have a table reportFilters which has the following column names:
The reportFilterId is auto increment. I want to insert a row in the table with the script below:
IF OBJECT_ID(N'ReportFilters', N'U') IS NOT NULL
BEGIN
IF NOT EXISTS (SELECT * FROM [ReportFilters]
WHERE ReportId IN (SELECT ReportId FROM [Reports] WHERE ReportType = 'Operational Insights Command Staff Dashboard') )
BEGIN
INSERT INTO [ReportFilters] Values(1, 'SelectView', 'Select Views', 13, 'Views','Views', 'SelectView', 'a', 'b', 'c' );
END
END
GO
But I am getting the following error:
Column name or number of supplied values does not match table definition.
Can I please get help on this ? Thanks in advance.
I think the problem is on inserted columns can't match with inserted data because that will instead by your table column order which is ReportFilterId instead of ReportId
So that there are 11 columns in your table but your statement only provides 10 columns.
I would use explicitly specify for inserted columns (inserted columns start from ReportId except your PK ReportFilterId column)
INSERT INTO [ReportFilters] (ReportId,ReportFilterName,ReportFilterTitle....)
Values (1, 'SelectView', 'Select Views', 13, 'Views','Views', 'SelectView', 'a', 'b', 'c' );

How can i use default value on postgres when query include null value

I use Postgres and I've integration app which write data to database. My column should not be null but my app send null value. I tried to set default value but query override this rule with null value. How can i handle this change without code.
My Column configuration looks like this.
If you won't or can't change the query in code, you have to use trigger
If you can change code structure and query:
If the column has a default value, then no need to send NULL value to query
-- Before change
insert into your_table (id, name, default_col) values
(1, 'name', null);
-- After change (remove null data)
insert into your_table (id, name) values
(1, 'name');
Or send default value in insert query
-- Before change
insert into your_table (id, name, default_col) values
(1, 'name', null);
-- After change (Use default keyboard)
insert into your_table (id, name, default_col) values
(1, 'name', default);

Hive - How to insert in a hive table an array of struct

So I learnt from here how to insert values into an array column:
INSERT INTO table
SELECT ARRAY("line1", "line2", "line3") as myArray
FROM source1;
And from here how to insert values into an struct column:
INSERT INTO table
SELECT NAMED_STRUCT('houseno','123','streetname','GoldStreet', 'town','London', 'postcode','W1a9JF') AS address
FROM source2;
Now I was trying to insert in the same way values in an array of structs. Which has got the following schema:
additionalattribute:array<struct<attribute_value:string,key:string,value:string>
I tried to extrapolate like this:
INSERT INTO table
ARRAY(NAMED_STRUCT('attribute_value','null','key','null','value','null')) as additionalattribute
FROM source2;
But it is not working. Does anyone know how to approach this issue?
you are missing the select statement after the table name. Demo
create table temp4
(
additionalattribute array<struct<attribute_value:string,key:string,value:string>>
);
INSERT INTO temp4 select
ARRAY(NAMED_STRUCT('attribute_value','null','key','null','value','null')) as additionalattribute
FROM (select '1' ) t;

SQL test if ARRAY contains integer

I have a SQL TABLE like
CREATE TABLE Test ( ContentArray INTEGER ARRAY )`.
I can insert an column with `INSERT INTO Test ( ContentArray ) VALUES ( ARRAY[1,2,3,4] )
But I don't know how to get all columns where ContentArray contains integer 3.
For example:
INSERT INTO Test ( ContentArray ) VALUES ( ARRAY[1,2] )
INSERT INTO Test ( ContentArray ) VALUES ( ARRAY[3,4] )
INSERT INTO Test ( ContentArray ) VALUES ( ARRAY[4,5] )
INSERT INTO Test ( ContentArray ) VALUES ( ARRAY[5,6] )
SELECT ContentArray FROM Test WHERE /* ContentArray contains 5 and 6 */
should return ARRAY[5,6].
Given the DBMS and some quick research, it looks like SQL2008 supports the ANY keyword to allow this type of query for array datatypes:
SELECT * FROM Test WHERE 3 = ANY (ContentArray);
I still wouldn't recommend using the array data type for anything non-trivial, I'm not sure what the performance of the above query would be like, but I'm sure it's not as good as a master table with children.

How to to get the value of an auto increment column in postgres from a .sql script file?

In postgres I have two tables like so
CREATE TABLE foo (
pkey SERIAL PRIMARY KEY,
name TEXT
);
CREATE TABLE bar (
pkey SERIAL PRIMARY KEY,
foo_fk INTEGER REFERENCES foo(pkey) NOT NULL,
other TEXT
);
What I want to do is to write a .sql script file that does the following
INSERT INTO foo(name) VALUES ('A') RETURNING pkey AS abc;
INSERT INTO bar(foo_fk,other) VALUES
(abc, 'other1'),
(abc, 'other2'),
(abc, 'other3');
which produces the error below in pgAdmin
Query result with 1 row discarded.
ERROR: column "abc" does not exist
LINE 3: (abc, 'other1'),
********** Error **********
ERROR: column "abc" does not exist
SQL state: 42703
Character: 122
Outside of a stored procedure how do a define a variable that I can use between statements? Is there some other syntax for being able to insert into bar with the pkey returned from the insert to foo.
You can combine the queries into one. Something like:
with foo_ins as (INSERT INTO foo(name)
VALUES ('A')
RETURNING pkey AS foo_id)
INSERT INTO bar(foo_fk,other)
SELECT foo_id, 'other1' FROM foo_ins
UNION ALL
SELECT foo_id, 'other2' FROM foo_ins
UNION ALL
SELECT foo_id, 'other3' FROM foo_ins;
Other option - use an anonymous PL/pgSQL block like:
DO $$
DECLARE foo_id INTEGER;
BEGIN
INSERT INTO foo(name)
VALUES ('A')
RETURNING pkey INTO foo_id;
INSERT INTO bar(foo_fk,other)
VALUES (foo_id, 'other1'),
(foo_id, 'other2'),
(foo_id, 'other3');
END$$;
You can use lastval() to ...
Return the value most recently returned by nextval in the current session.
This way you do not need to know the name of the seqence used.
INSERT INTO foo(name) VALUES ('A');
INSERT INTO bar(foo_fk,other) VALUES
(lastval(), 'other1')
, (lastval(), 'other2')
, (lastval(), 'other3')
;
This is safe because you control what you called last in your own session.
If you use a writable CTE as proposed by #Ihor, you can still use a short VALUES expression in the 2nd INSERT. Combine it with a CROSS JOIN (or append the CTE name after a comma (, ins) - same thing):
WITH ins AS (
INSERT INTO foo(name)
VALUES ('A')
RETURNING pkey
)
INSERT INTO bar(foo_fk, other)
SELECT ins.pkey, o.other
FROM (
VALUES
('other1'::text)
, ('other2')
, ('other3')
) o(other)
CROSS JOIN ins;
Another option is to use currval
INSERT INTO foo
(name)
VALUES
('A') ;
INSERT INTO bar
(foo_fk,other)
VALUES
(currval('foo_pkey_seq'), 'other1'),
(currval('foo_pkey_seq'), 'other2'),
(currval('foo_pkey_seq'), 'other3');
The automatically created sequence for serial columns is always named <table>_<column>_seq
Edit:
A more "robust" alternative is to use pg_get_serial_sequence as Igor pointed out.
INSERT INTO bar
(foo_fk,other)
VALUES
(currval(pg_get_serial_sequence('public.foo', 'pkey')), 'other1'),
(currval(pg_get_serial_sequence('public.foo', 'pkey')), 'other2'),
(currval(pg_get_serial_sequence('public.foo', 'pkey')), 'other3');