concatenate column values by jumping over nulls - mysql

if col1 has value lorem or null
col2 - ipsum or null
col3 - dolor or null
col4 should be lorem,ipsum,dolor if there is no null inside preceding columns.
if, for example, col2 is null the result should be lorem,dolor
something like - update table set col4 = concat(col1, col2, col3) - but jumping over nulls
Is this possible using mysql?

You could use CONCAT_WS:
CONCAT_WS() does not skip empty strings. However, it does skip any NULL values after the separator argument.
update table set col4 = concat_ws(',', col1, col2, col3);
To avoid running update every time I suggest to use generated column:
CREATE TABLE t(id INT, col1 TEXT, col2 TEXt, col3 TEXT,
col4 TEXT AS (concat_ws(',', col1, col2, col3))
)
db<>fiddle demo

Related

How can I sum two columns in SQL?

I have a table with 2 columns:
CREATE TABLE Numbers(
col1 float,
col2 float
);
INSERT INTO Numbers(col1, col2)
VALUES('0.6', '1.5'),('2.7', '1.8');
How can I create a third column with the sum of col1 and col2?
First, create col3 using the ALTER TABLE command.
Then update it with the sums.
UPDATE numbers SET col3 = col1 + col2;
I would suggest a calculated column - that way if col1 or col2 are updated, col3 will automatically reflect the correct value; storing mutable data is gnerally not a good idea as it easily leads to inconsistencies.
alter table Numbers add column col3 float as (col1 + col2) stored;
Side note - float is rarely the correct choice of data type, probably you should be using a decimal.
Select *, col1 +col2 as col3 from numbers

UPSERT with non-unique index

I need to implement concurrent-safe UPSERT using a non-unique key and avoid unnecessary auto-increment of ID.
Traditional INSERT ... ON DUPLICATE KEY doesn't work for me, so I'm performing:
INSERT INTO table (col1, col2, col3, col4, col5)
SELECT 1, 2, 'value3', 'value4', 'value5'
WHERE NOT EXISTS (SELECT 1
FROM table
WHERE col3 = 'value3'
AND col4 = 'value4'
AND col5 = 'value5')
then if it results in no row inserted, I'm performing:
UPDATE table
SET col1 = col1 + 1,
col2 = MAX(col2, 2)
WHERE col3 = 'value3'
AND col4 = 'value4'
AND col5 = 'value5'
There's an index:
CREATE INDEX ON table (col3, col4, col5)
It is non-unique as there are legacy data that does not allow me to declare it unique. Newer records, however, should not have duplicated (col3, col4, col5) rows.
Unsurprisingly, using the given INSERT statement I'm getting mixed results trying to execute it concurrently from two sessions. I can see the second session blocking until the first one commits its transaction, but then the second transaction is also able to insert a new row sometimes (or sometimes it achieves the expected of avoiding to insert a duplicate (col3, col4, col5) row).
I'm currently performing manual unique-check after the insert:
SELECT COUNT(1)
FROM table
WHERE col3 = 'value3'
AND col4 = 'value4'
AND col5 = 'value5'
but I've also tried:
INSERT INTO table (col1, col2, col3, col4, col5)
SELECT 1, 2, 'value3', 'value4', 'value5'
WHERE NOT EXISTS (SELECT 1
FROM table
WHERE col3 = 'value3'
AND col4 = 'value4'
AND col5 = 'value5'
FOR UPDATE)
which appears to work with the examples I'm always getting a duplicate (col3, col4, col5) row, otherwise. Is the given FOR UPDATE usage reliable for the purpose of ensuring no duplicate (col3, col4, col5) row will be inserted?
I'm using READ-COMMITTED transaction isolation.
MySQL 8.0.13 and higher supports functional key parts that index expression values rather than column or column prefix values. (link)
Because you have a unique field, i am assuming this is col, you can add an index like:
CREATE unique INDEX idx2 ON `mytable` ((col1>42),col3, col4, col5);
Where 42 should be the next auto-increment for col1.
Newly create records will be unique on the 3 columns, without affecting your 'old' data.
It is even possible to update the old data (as long as col1<=42).

how to find out a result set by which column ? if we write 3 columns in where clause with OR Operators on single table

I have a database table. That table has 4 columns. In 3 columns members(values) want to access the 4th column value.
So here i don't want to write same query for every member. I want to write only single query. So is it possible with single query? If possible how I can know which column has given those result set?
select 4thcolumn from tablename where lstcolumn=?1 or 2ndcolumn=?2 or 3rdcolumn=?3;
Using OR is a solution (but that requires you to repeat the parameter three times):
SELECT col4 FROM mytable col1 =:myvalue OR col2 =:myvalue OR col3 = :myvalue;
One solution to shorten the query (and pass a unique parameter) is to use IN:
SELECT col4 FROM mytable WHERE :myvalue IN (col1, col2, col3)
If you want to know which column matched, then this gets longer. In MySQL you can do:
SELECT
col4,
col1 = :myvalue is_col1,
col2 = :myvalue is_col2,
col3 = :myvalue is_col3
FROM mytable
WHERE :myvalue IN (col1, col2, col3)
This adds three columns in the result set: is_col1, is_col2, is_col3; the column(s) that matched will have value 1, other(s) will show 0.

Check Constraint based on other column value

I have a table named Table1 with three columns col1, col2, col3.
col1 can have one of the three values(1 or 2 or 3).
I need to add a check constraint such that it checks, if col1 has value 1 then the values of col2 and col3 should be same else if col1 has values 2 or 3, then col2 and col3 values may or may not be same.
Can anyone tell me how to add the constraint for this ?
Thanks in advance.
You can add a check constraint like this:
ALTER TABLE Table1 ADD CONSTRAINT chk_table1_cols
CHECK ( (col1 = 1 AND col2 = col3) OR (col1 IN (2, 3)) );
Note that "is the same" presumes that the values are not NULL. That logic can be added, if you want to consider NULL values as equal.
You can express these condition with a series of logical operators:
(col IN (1, 2, 3)) AND (col2 = col3 OR col1 IN (2, 3)
I didn't verify (I don't have MySql) but in Oracle the following works:
ALTER TABLE Table1 ADD
(
CONSTRAINT CHK_1 CHECK ((col1 BETWEEN 1 AND 3) AND (col1 <> 1 OR col2=col3))
)

Conditionally execute query

Is there a way to execute a query, depending on the result of a certain column?
My table has a column col1, which could be NULL. I want to check first. If col1 is not NULL, execute another query, if col1 is NULL, do nothing (or return something else).
In pseudocode it could look like this:
IF (SELECT col1 IS NUT NULL FROM `tab1`)
THEN (SELECT col1, col2, col3 FROM `tab1`)
PS: I execute those queries from PHP, so it would also be possible, to check the result of col1 with PHP, though I would prefer to use plain SQL.
the where clause is your if
select col1, col2, col3 FROM `tab1`
where col1 IS NOT NULL