Multiple columns in one SQL - sql

Can i insert multiple values from different columns in one?
i have:
ref | alt | couple_refalt
--------------------------
A C AC ( i want)
A G AG Etc...
Is there a simple way?
I tried with:
INSERT INTO refalt(couple_refalt)
SELECT ref||alt
FROM refalt
WHERE ref='A';
Is it correct?
But it gives me the error:
null value in column violates not-null constraint
Postgres want a value for each colum, why can't i update or insert into specific column?

Storing comma separated value is not the SQLish way to store values. What you seem to want is a computed column. Postgres does not support that directly. One method is to declare a view:
create view v_refault
select r.*, ref || ',' || alt
from refault;
Other possibilities are:
Define a trigger to maintain the value.
Concatenate the values at the application level.
Use a function-based method to emulate a computed column.

In order to insert two values into one column, you need to concatenate them. In postgresql the syntax is the following.
SELECT ref::text || ', ' || alt::text FROM refalt
If you want more details, here is the string documentation

Related

Check if CSV string column contains desired values

I am new to PostgreSQL and I want to split string of the following format:
0:1:19
with : as delimiter. After split, I need to check if this split string contains either 0 or 1 as a whole number and select only those rows.
For example:
Table A
Customer
role
A
0:1:2
B
19
C
2:1
I want to select rows which satisfy the criteria of having whole numbers 0 or 1 in role.
Desired Output:
Customer
role
A
0:1:2
C
2:1
Convert to an array, and use the overlap operator &&:
SELECT *
FROM tbl
WHERE string_to_array(role, ':') && '{0,1}'::text[];
To make this fast, you could support it with a GIN index on the same expression:
CREATE INDEX ON tbl USING GIN (string_to_array(role, ':'));
See:
Can PostgreSQL index array columns?
Check if value exists in Postgres array
Alternatively consider a proper one-to-many relational design, or at least an actual array column instead of the string. Would make index and query cheaper.
We can use LIKE here:
SELECT Customer, role
FROM TableA
WHERE ':' || role || ':' LIKE '%:0:%' OR ':' || role || ':' LIKE '%:1:%';
But you should generally avoid storing CSV in your SQL tables if your design would allow for that.

Oracle Selecting Columns with IN clause which includes NULL values

So I am comparing two Oracle databases by grabbing random rows in database A, and searching for these rows in database B based off their key columns. Then I compare the rows which are returned in java.
I am using the following query to find rows in database B using the key columns from database A:
select * from mytable
Where (Key_Column_A,Key_Column_B,Key_Column_C)
in (('1','A', 'cat'),('2','B', 'dog'),('3','C', ''));
This works just fine for the first two sets of keys, but the third key('3','C', '') does not work because there is a null value in the third column. Changing the statement to ('3','C', NULL) or changing the SQL to
select * from mytable
Where (Key_Column_A,Key_Column_B,Key_Column_C)
in ((('1','A', 'cat'),('2','B', 'dog'),('3','C', ''))
OR (Key_Column_A,Key_Column_B,Key_Column_C) IS NULL);
will not work either.
Is there a way to include a null column in an IN clause? And if not, is there a way to efficiently do the same thing? (My only solution currently is to create a check to make sure there are no nullable columns in my keys which would make this process rather unefficient and somewhat messy).
You can use it this way. I think it would work.
select * from mytable
Where (NVL(Key_Column_A,''),NVL(Key_Column_B,''),NVL(Key_Column_C,''))
in (('1','A', 'cat'),('2','B', 'dog'),('3','C', ''));
I am not sure about this (Key_Column_A,Key_Column_B,Key_Column_C) IS NULL. Wouldn't this imply that all of the columns (A,B,C) are NULL ?

update a column using values from a different column of the same table

Given the DB table:
CREATE TABLE stuff (
id text not null,
other text
);
That has lots of id values but has all other set to NULL, is there an elegant way to update the table so that all other rows get updated to OTHER-{id} (where {id} is the value of the id column)?
(It must work in Postgresql)
Only a simple update statement is needed with some string concatenation (||):
update stuff
set other = 'OTHER-' || id
You'll want to use the following:
UPDATE stuff
SET other = 'OTHER-' || id;
UPDATE is the keyword used to identify which table you'd like to update.
SET is the keyword used to identify which column you'd like to update, and this is where you choose to assign the column to:
'OTHER-' || id
'OTHER-' being a string
|| a shorthand way to concatenate
id the value you want.
Another way of writing this would be
other = concat('OTHER-',id);
I along with many others will find the || method to be much cleaner, but it's worth knowing about the dedicated function as well.

Part replace a record in SQL

I need to mask data in my tables, for example data like:
ABCDEFG
XYZABCD
LMNOPQR
Should appear like:
AB*****
XY*****
LM*****
What update query can I use? Also, can I use a single query for updating multiple columns?
You can just mask it when showing the data
select stuff(stuff(stuff(col,3,3,'*'),7,3,'*'),10,3,'*')) as col from table
Suppose the column you want to mask is called column from table table, than you can use the following query, which is standard in SQL, to update the value in the column:
update table
set column = substring(column from 1 for 2) || '****';
If on the other hand you want only to select the values to show them, you can use the following query:
select substring(column from 1 for 2) || '****'
from table;

How to get unique values from each column based on a condition?

I have been trying to find an optimal solution to select unique values from each column. My problem is I don't know column names in advance since different table has different number of columns. So first, I have to find column names and I could use below query to do it:
select column_name from information_schema.columns
where table_name='m0301010000_ds' and column_name like 'c%'
Sample output for column names:
c1, c2a, c2b, c2c, c2d, c2e, c2f, c2g, c2h, c2i, c2j, c2k, ...
Then I would use returned column names to get unique/distinct value in each column and not just distinct row.
I know a simplest and lousy way is to write select distict column_name from table where column_name = 'something' for every single column (around 20-50 times) and its very time consuming too. Since I can't use more than one distinct per column_name, I am stuck with this old school solution.
I am sure there would be a faster and elegant way to achieve this, and I just couldn't figure how. I will really appreciate any help on this.
You can't just return rows, since distinct values don't go together any more.
You could return arrays, which can be had simpler than you may have expected:
SELECT array_agg(DISTINCT c1) AS c1_arr
,array_agg(DISTINCT c2a) AS c2a_arr
,array_agg(DISTINCT c2b) AS c2ba_arr
, ...
FROM m0301010000_ds;
This returns distinct values per column. One array (possibly big) for each column. All connections between values in columns (what used to be in the same row) are lost in the output.
Build SQL automatically
CREATE OR REPLACE FUNCTION f_build_sql_for_dist_vals(_tbl regclass)
RETURNS text AS
$func$
SELECT 'SELECT ' || string_agg(format('array_agg(DISTINCT %1$I) AS %1$I_arr'
, attname)
, E'\n ,' ORDER BY attnum)
|| E'\nFROM ' || _tbl
FROM pg_attribute
WHERE attrelid = _tbl -- valid, visible table name
AND attnum >= 1 -- exclude tableoid & friends
AND NOT attisdropped -- exclude dropped columns
$func$ LANGUAGE sql;
Call:
SELECT f_build_sql_for_dist_vals('public.m0301010000_ds');
Returns an SQL string as displayed above.
I use the system catalog pg_attribute instead of the information schema. And the object identifier type regclass for the table name. More explanation in this related answer:
PLpgSQL function to find columns with only NULL values in a given table
If you need this in "real time", you won't be able to archive it using a SQL that needs to do a full table scan to archive it.
I would advise you to create a separated table containing the distinct values for each column (initialized with SQL from #Erwin Brandstetter ;) and maintain it using a trigger on the original table.
Your new table will have one column per field. # of row will be equals to the max number of distinct values for one field.
For on insert: for each field to maintain check if that value is already there or not. If not, add it.
For on update: for each field to maintain that has old value != from new value, check if the new value is already there or not. If not, add it. Regarding the old value, check if any other row has that value, and if not, remove it from the list (set field to null).
For delete : for each field to maintain, check if any other row has that value, and if not, remove it from the list (set value to null).
This way the load mainly moved to the trigger, and the SQL on the value list table will super fast.
P.S.: Make sure to pass all you SQL from trigger to explain plan to make sure they use best index and execution plan as possible. For update/deletion, just check if old value exists (limit 1).