SQL updating table - mysql

col1 | col2 | col3
-----------------------------
1 | 1 | somestring 12
1 | 2 | somestring sd
2 | 1 | somestring gvr
2 | 2 | somestring 46
3 | 1 | somestring sdf
3 | 2 | somestring 4
....
i want to UPDATE col3 WHERE col2 = 2
to be a CONCAT of col1 with col3
and REPLACE all ' ' with '-'.
Also if col1 < 10 add a leading '0' so '1' would be '01'
in total the value of col3 should be '01-somestring-sd'
can someone please help me with the statement?

Create data/insert data
CREATE TABLE Table1
(`col1` INT, `col2` INT, `col3` VARCHAR(255))
;
INSERT INTO Table1
(`col1`, `col2`, `col3`)
VALUES
(1, 1, 'somestring 12'),
(1, 2, 'somestring sd'),
(2, 1, 'somestring gvr'),
(2, 2, 'somestring 46'),
(3, 1, 'somestring sdf'),
(3, 2, 'somestring 4')
;
Query
UPDATE
Table1
SET
col3 =
CASE
WHEN col1 < 10
THEN REPLACE(CONCAT('0', col1, '-', col3), ' ', '-')
ELSE REPLACE(CONCAT(col1, '-', col3), ' ', '-')
END
WHERE
col2 = 2
Result
1 queries executed, 1 success, 0 errors, 0 warnings
Query: UPDATE Table1 SET col3 = CASE WHEN col1 < 10 THEN REPLACE(CONCAT('0', col1, '-', col3), ' ', '-') ELSE REPLACE(CONCAT(col1, '-',...
3 row(s) affected
Query
SELECT * FROM Table1
Result
col1 col2 col3
------ ------ ------------------
1 1 somestring 12
1 2 01-somestring-sd
2 1 somestring gvr
2 2 02-somestring-46
3 1 somestring sdf
3 2 03-somestring-4

UPDATE TABLE1 SET COL3=CONCAT(IF(COL1 < 10,0,''),COL1,REPLACE(COL3, ' ', '-' )) WHERE COL2=2
Try above code.
Hope this will helps.

Try this
Update table1
set
col3 = concat((case when col1>10 then '0'+col1 else col1 end),'-',REPLACE(COL3, ' ','-' ))
where col2=2

just use Concat and Replace
update table_name as t set t.col3 =
CONCAT(if(t.col1<10,0,''),t.col1,REPLACE(t.col‌​3,' ','-')) where
t.col2 =2;

Related

Need some help to clean duplicates in MySQL table which didn't have constraint

I've inherited some MySQL table that was designed without correct constraint so it gets filled with some duplicate rows which I need to remove. The problem that across duplicate rows data isn't usually consistent, see example below:
id
request_id
guid_id
details
flag
1
10
fh82EN
help me
1
2
11
fh82EN
3
12
fh82EN
assistance required
1
4
12
fh82EN
assistance required
1
5
13
fh82EN
6
13
fh82EN
assist me.
1
7
13
fh82EN
8
14
fh82EN
Records with id: 1,2,8 perfectly fine. For duplicate records with id 3, 4 I have designed the query below which works fine and removes all duplicates without an issue:
DELETE IR.*
FROM platform.temp IR
WHERE id IN (
SELECT maxId AS id FROM (
SELECT MAX(id) as maxId, request_id, guid_id
FROM platform.temp
GROUP BY request_id, guid_id
HAVING COUNT(*) > 1
) AS T
);
The problem is records with id 5,6,7. You can see that the same record by (guid_id and request_id) is not consistent. So, my previous query will delete records with content too because of MAX(id). I have designed a query that fixes these records, but we are talking about a huge database and this query is painfully slow:
UPDATE platform.temp AS DEST_T
INNER JOIN (
SELECT request_id, guid_id, details, flag FROM platform.temp WHERE details IS NOT NULL AND details != ''
) AS SOURCE_T
SET DEST_T.details = SOURCE_T.details, DEST_T.flag = SOURCE_T.flag
WHERE DEST_T.guid_id = SOURCE_T.guid_id AND DEST_T.request_id = SOURCE_T.request_id;
How can I change my delete query that it will order my subgroup by field details and will select not MAX(id) but first id, so I will be sure that last row in subgroup will always be populated with value and will left?
MySQL version: 5.6.40-log
UPDATE1:
The desired outcome after cleaning the table should be as follow:
id
request_id
guid_id
details
flag
1
10
fh82EN
help me
1
2
11
fh82EN
3
12
fh82EN
assistance required
1
6
13
fh82EN
assist me.
1
8
14
fh82EN
Use a self join of the table:
DELETE t1
FROM tablename t1 INNER JOIN tablename t2
ON t2.request_id = t1.request_id AND t2.guid_id = t1.guid_id
WHERE (t2.id < t1.id AND COALESCE(t1.details, '') = '')
OR
(t2.id > t1.id AND COALESCE(t2.details, '') <> '');
This will keep 1 row for each request_id and guid_id combination, not necessarily the one with the min id.
See the demo.
Another way to do it, with conditional aggregation:
DELETE t1
FROM tablename t1 INNER JOIN (
SELECT request_id, guid_id,
MIN(id) min_id,
MIN(CASE WHEN COALESCE(details, '') <> '' THEN id END) min_id_not_null
FROM tablename
GROUP BY request_id, guid_id
) t2 ON t2.request_id = t1.request_id AND t2.guid_id = t1.guid_id
WHERE t1.id <> COALESCE(t2.min_id_not_null, t2.min_id);
This will keep the row with the min id under your conditions, but maybe its performance would not be that good compared to the 1st query.
See the demo.
Another way is to emulate the ROW_NUMBER ad then perform the delete operation.
DELETE FROM test
WHERE id NOT IN (select id
from (SELECT id,
#row_number := CASE WHEN #last_request_id <> x.request_id + x.guid_id
THEN 1 ELSE #row_number + 1 END AS row_num,
#last_request_id := x.request_id + x.guid_id
FROM test x
CROSS JOIN (SELECT #row_number := 0, #last_request_id := null, #last_guid_id := null) y
ORDER BY request_id, guid_id, details DESC) temp
where row_num = 1);
Demo.
As i said in the comments i would use it with row_numbers, which in mysql 8 would look much more nicer
CREATE TABLE temp
(`id` varchar(4), `request_id` varchar(12), `guid_id` varchar(9), `details` varchar(21), `flag` varchar(6))
;
INSERT INTO temp
(`id`, `request_id`, `guid_id`, `details`, `flag`)
VALUES
('1', '10', 'fh82EN', 'help me', '1'),
('2', '11', 'fh82EN', NULL, NULL),
('3', '12', 'fh82EN', 'assistance required', '1'),
('4', '12', 'fh82EN', 'assistance required', '1'),
('5', '13', 'fh82EN', NULL, NULL),
('6', '13', 'fh82EN', 'assistance required', '1'),
('7', '13', 'fh82EN', NULL, NULL),
('8', '14', 'fh82EN', NULL, NULL)
;
DELETE t1
FROM temp t1 INNER JOIN
(SELECT `id`
, IF(#request = `request_id` AND #guid = guid_id, #rn:= #rn+1,#rn := 1) rn
,#request := `request_id` as request_id
,#guid := guid_id as guid_id
fROM temp,(SELECT #request := 0, #guid := '',#rn := 0) t1
ORDER BY `guid_id`,`request_id`,`details` DESC, id) t2 ON
t1.`id` = t2.`id` AND rn > 1
SELECT * FROM temp
id | request_id | guid_id | details | flag
:- | :--------- | :------ | :------------------ | :---
1 | 10 | fh82EN | help me | 1
2 | 11 | fh82EN | null | null
3 | 12 | fh82EN | assistance required | 1
6 | 13 | fh82EN | assistance required | 1
8 | 14 | fh82EN | null | null
db<>fiddle here

How to get count of columns that are having null values for a given row in sql?

I have a table that are having 115 columns.
Out of 7 columns I need to get the count of columns that are having not null values for a given row.
One method is to use case and +:
select t.*,
( (case when col1 is not null then 1 else 0 end) +
(case when col2 is not null then 1 else 0 end) +
(case when col3 is not null then 1 else 0 end) +
(case when col4 is not null then 1 else 0 end) +
(case when col5 is not null then 1 else 0 end) +
(case when col6 is not null then 1 else 0 end) +
(case when col7 is not null then 1 else 0 end)
) as cnt_not_nulls_in_row
from t;
In MySQL, this can be simplified to:
select t.*,
( (col1 is not null ) +
(col2 is not null ) +
(col3 is not null ) +
(col4 is not null ) +
(col5 is not null ) +
(col6 is not null ) +
(col7 is not null )
) as cnt_not_nulls_in_row
from t;
You may first query the given row from the table using the primary key and the use COUNT to count the number of columns from the queried row having null value, as follows:
WITH derived_row as
(SELECT col1, col2, col3, col4, col5, col6, col7 FROM table WHERE primary_key=key)
SELECT COUNT(CASE
WHEN col1 IS NULL THEN 1
WHEN col2 IS NULL THEN 1
WHEN col3 IS NULL THEN 1
WHEN col4 IS NULL THEN 1
WHEN col5 IS NULL THEN 1
WHEN col6 IS NULL THEN 1
WHEN col7 IS NULL THEN 1
END) AS null_column_count
FROM derived_row;

How to return a column value in case result is empty in SQL?

I am using a SQL query to fetch 3 column values. Sometimes I don't get records. What I need is a query that always returns field1, even if field2 and field3 are NULL.
I'm using field1 as input:
AND field1 IN('test1', 'test2', 'test3')
How can I always return these values?
Complete SQL query:
SELECT field1, field2, field3
FROM
(
SELECT
name1.field1,
name1.field2,
name3.field3,
name4.field4,
#pl2 := IF( #pl1 = name1.field1, #pl2, 1) as pl2,
#pl1 := name1.field1
FROM
(
SELECT
#pl1 := NULL,
#pl2 := 0
)
R,
db1.field5 AS name1,
db1.field6 AS name2,
db1.field7 AS name3,
db1.field8 AS name4
WHERE
name2.field9 = name1.field9
AND name3.field10 = name2.field10
AND name4.field11 = name3.field3
AND field1 IN('test1', 'test2', 'test3')
AND field12 LIKE 'helloworld'
AND name2.field13 LIKE 'helloworld'
GROUP BY name1.field1
ORDER BY name1.field14 desc
)
A
WHERE
pl2 = 1
Current output (wrong):
AND field1 IN('test1', 'test2', 'test3')
field1 | field2 | field3
test3 | hello | world
AND field1 IN('test1', 'test2')
field1 | field2 | field3
Needed output:
AND field1 IN('test1', 'test2', 'test3')
field1 | field2 | field3
test1 | [this part doesn't matter]
test2 | [this part doesn't matter]
test3 | hello | world
AND field1 IN('test1', 'test2')
field1 | field2 | field3
test1 | [this part doesn't matter]
test2 | [this part doesn't matter]
As a said in comment, I couldn't test as there are not (partial) script to CREATE TABLE and sample data insert.
I thought something like that: can you see if it works for you?
SELECT NAME1.FIELD1
, NAME1.FIELD2
, NAME3.FIELD3
, NAME4.FIELD4
, #pl2 := IF( #pl1 = NAME1.FIELD1, #pl2, 1) AS pl2
, #pl1 := NAME1.FIELD1
FROM FIELD5 AS NAME1
CROSS JOIN (SELECT #pl1 := NULL, #pl2 := 0) R
INNER JOIN DB1.FIELD6 AS NAME2 ON NAME1.FIELD9 = NAME2.FIELD9
LEFT JOIN DB1.FIELD7 AS NAME3 ON NAME3.FIELD10 = NAME2.FIELD10
LEFT JOIN DB1.FIELD8 AS NAME4 ON NAME4.FIELD11 = NAME3.FIELD3
WHERE FIELD1 IN ('test1', 'test2', 'test3')
AND name2.field13 LIKE 'helloworld'
GROUP BY NAME1.FIELD1
ORDER BY NAME1.FIELD14 DESC
;
What if you say SELECT COALESCE(field1, field2, field3) instead

Group by with text and date time combination

I have a table
id col1 col2 namecol1 datetime1 teamcol1 namecol2 datetime2
1 12345 2345 name1 2014-10-13 11:57:24.713 teama
2 12345 2345 name1 2014-10-13 11:57:24.713 teamb abc 2014-11-29 09:55:38.533
3 12345 2345 name1 2014-10-13 11:57:24.713 teamb bcd 2014-12-02 06:35:38.917
4 12345 2345 name1 2014-10-13 11:57:24.713 teamc def 2014-12-22 11:57:54.863
5 12345 2345 name1 2014-10-13 11:57:24.713 teamd efg 2015-01-03 13:28:24.717
I need this output:
col1 col2 Team1 DateTime1 Team2 DateTime2 Team3 DateTime3
12345 2345 bcd 2014-12-02 06:35:38.917 def 2014-12-22 11:57:54.863 efg 2015-01-03 13:28:24.717
I tried this query:
SELECT
MAX(CASE WHEN teamcol1='teamb' THEN namecol2 END) AS Team1,
CONVERT(DATE, MAX(CASE WHEN teamcol1='teamb' THEN datetime2 END), 105) AS DateTime1,
MAX(CASE WHEN teamcol1='teamc' THEN namecol2 END) AS PRECON_AUDIT,
CONVERT(DATE,MAX(CASE WHEN teamcol1='teamc' THEN datetime2 END), 105) AS DateTime2,
MAX(CASE WHEN teamcol1 IN ('teamd') THEN namecol2 END) AS Team3,
CONVERT(DATE,MAX(CASE WHEN teamcol1 IN ('teamd') THEN datetime2 END),105) AS DateTime3,
col1, col2
FROM
(SELECT *
FROM table1) Z
WHERE
col1 = '12345'
GROUP BY
col1, col2
Output of this query:
col1 col2 Team1 DateTime1 Team2 DateTime2 Team3 DateTime3
12345 2345 abc 2014-12-02 06:35:38.917 def 2014-12-22 11:57:54.863 efg 2015-01-03 13:28:24.717
I am using SQL Server 2008.
Thanks in advance.
[EDIT]
Table1 is like audit table which will have multiple entries with different combination of col1,col2.
I need to display for each combination of col1,col2 different team names and with appropriate namecol2 and datetime2 columns.
When i use the query mentioned above it is giving me the output correctly if there is no repetition in teamcol1. If there is a repetition in teamcol1 (as mentioned in question) it is giving me the wrong namecol2.
In case of repetition in teamcol1 i need latest namecol2 and datetime2 ( from the table i need namecol2 -- bcd and datetime2 -- 2014-12-02 06:35:38.917)
At first make a list of all groups (DISTINCT col1, col2).
Then for each group find one row with the latest datetime2. Do it three times, for each teamb, teamc, teamd.
You can put complex query inside OUTER APPLY with whatever logic and ordering you need.
DECLARE #T TABLE (id int, col1 int, col2 int, namecol1 varchar(255), [datetime1] datetime, teamcol1 varchar(255), namecol2 varchar(255), [datetime2] datetime);
INSERT INTO #T (id, col1, col2, namecol1, datetime1, teamcol1, namecol2, datetime2) VALUES (1, 12345, 2345, 'name1', '2014-10-13 11:57:24.713', 'teama', NULL, NULL);
INSERT INTO #T (id, col1, col2, namecol1, datetime1, teamcol1, namecol2, datetime2) VALUES (2, 12345, 2345, 'name1', '2014-10-13 11:57:24.713', 'teamb', 'abc', '2014-11-29 09:55:38.533');
INSERT INTO #T (id, col1, col2, namecol1, datetime1, teamcol1, namecol2, datetime2) VALUES (3, 12345, 2345, 'name1', '2014-10-13 11:57:24.713', 'teamb', 'bcd', '2014-12-02 06:35:38.917');
INSERT INTO #T (id, col1, col2, namecol1, datetime1, teamcol1, namecol2, datetime2) VALUES (4, 12345, 2345, 'name1', '2014-10-13 11:57:24.713', 'teamc', 'def', '2014-12-22 11:57:54.863');
INSERT INTO #T (id, col1, col2, namecol1, datetime1, teamcol1, namecol2, datetime2) VALUES (5, 12345, 2345, 'name1', '2014-10-13 11:57:24.713', 'teamd', 'efg', '2015-01-03 13:28:24.717');
WITH
CTE_Groups
AS
(
SELECT DISTINCT col1, col2
FROM #T
)
SELECT *
FROM
CTE_Groups
OUTER APPLY
(
SELECT TOP(1)
TT.namecol2 AS Team1
, TT.[datetime2] AS DateTime1
FROM #T AS TT
WHERE
TT.teamcol1 = 'teamb'
AND TT.col1 = CTE_Groups.col1
AND TT.col2 = CTE_Groups.col2
ORDER BY TT.[datetime2] DESC
) OA_teamb
OUTER APPLY
(
SELECT TOP(1)
TT.namecol2 AS Team2
, TT.[datetime2] AS DateTime2
FROM #T AS TT
WHERE
TT.teamcol1 = 'teamc'
AND TT.col1 = CTE_Groups.col1
AND TT.col2 = CTE_Groups.col2
ORDER BY TT.[datetime2] DESC
) OA_teamc
OUTER APPLY
(
SELECT TOP(1)
TT.namecol2 AS Team3
, TT.[datetime2] AS DateTime3
FROM #T AS TT
WHERE
TT.teamcol1 = 'teamd'
AND TT.col1 = CTE_Groups.col1
AND TT.col2 = CTE_Groups.col2
ORDER BY TT.[datetime2] DESC
) OA_teamd
Result set:
col1 col2 Team1 DateTime1 Team2 DateTime2 Team3 DateTime3
12345 2345 bcd 2014-12-02 06:35:38.917 def 2014-12-22 11:57:54.863 efg 2015-01-03 13:28:24.717
If there is no teamb for a certain combination of col1 and col2, there will be NULLs in Team1 and DateTime1. Same for teamc and teamd.

Mysql query with multiple conditions

Simply put : I have a table with
columns : col1 col2 col3 col4 col5 col6 col7
datas : val1 2 toto t f f f
val1 2 toto t t f f
val1 2 toto f t f t
val2 3 tata t f f t
val5 4 tutu f t f f
i want a query to give me this : val1 2 toto t t f t (the condition is where col2 = 2) = > the first 3 lines in one line with t when t is found in any of the last 4 columns
Is there any way to achieve this in one query ?
True and false are internally 1 and 0. Therefore a simple
SELECT
col1, col2, col3, max(col4),
max(col5), max(col6), max(col7),
sum(col6 + col7) as one_of_them_is_greater_0_meaning_true
from your_table
group by
col1, col2, col3
will do.
EDIT: Since you're storing varchars (bad idea), replace each true/false column with
CASE WHEN col = 't' THEN 1 ELSE 0 END /*of course replacing column name appropriatelly*/
EDIT 2:
SELECT
col1, col2, col3, max(CASE WHEN col4 = 't' THEN 1 ELSE 0 END),
max(CASE WHEN col5 = 't' THEN 1 ELSE 0 END), max(CASE WHEN col6 = 't' THEN 1 ELSE 0 END), max(CASE WHEN col7 = 't' THEN 1 ELSE 0 END),
sum(CASE WHEN col6 = 't' THEN 1 ELSE 0 END + CASE WHEN col7 = 't' THEN 1 ELSE 0 END) as one_of_them_is_greater_0_meaning_true
from Table1
where col2 = 2
group by
col1, col2, col3
see it working live in an sqlfiddle
1 is true, 0 is false. You can replace that again if you want to. And use alias names for columns of course. It's just a proof of concept.
Ok then you can use
SELECT field1, field2, field3,
MAX(IF(field4 = 't',1,0)) as is_any_field4_true,
MAX(IF(field5 = 't',1,0)) as is_any_field5_true,
MAX(IF(field6 = 't',1,0)) as is_any_field6_true,
MAX(IF(field7 = 't',1,0)) as is_any_field7_true
GROUP BY field1, field2, field3