How do I execute a query using INSERT INTO and WITH statement? - mysql

INSERT INTO tablename( columnname1, columnname2, columnaname2)
WITH
a AS
SELECT * FROM tablename
WHERE condition
),
b AS
SELECT * FROM tablename
WHERE condition
)
I have a couple lines of query below where I use an DISTINCT statement but would like to know for now whether my query above is correct or not.

WITH? This is going to be introduced in MySQL 8.0. Are you using a preview release? Otherwise you won't be able to use WITH in MySQL.
Anyway: A WITH clause belongs at the beginning of the statement: WITH ... INSERT .... See here: https://dev.mysql.com/doc/refman/8.0/en/with.html.
It seems, however, you are not even using your CTEs a and b. Your CTEs are also lacking parentheses. Your statement should look something like this for instance:
WITH a AS (SELECT * FROM tablename WHERE condition)
, b AS (SELECT * FROM tablename WHERE condition)
INSERT INTO tablename(columnname1, columnname2, columnaname2)
SELECT col1, col2, col3 FROM a
UNION ALL
SELECT col1, col2, col3 FROM b;

Related

Checking multiple columns for one value with greater than or equal (>=)

Let's say i'm having a table like this:
id,col1,col2,col3,col4
I wish to check if any of col1,col2,col3,col4 are greater than or equal 10
The idea was smth like
SELECT * FROM table WHERE (col1 >= 10 OR col2 >= 10 OR col3 >= 10 OR col4 >= 10);
Is there any more optimized way?
I thought that I could use IN, but as don't have any clue how to use >= in it.
Assuming none of the values are NULL, you can use greatest():
SELECT *
FROM table
WHERE GREATEST(col1, col2, col3, col5) >= 10;
This is no more efficient, but it is shorter.
That is how I might write the script.
You could try the below, but performance is likely to be degraded (not sure as don't have MySQL setup)
Test Table Setup
CREATE TABLE tbl_test (
col1 INT
,col2 INT
,col3 INT
);
INSERT INTO tbl_test (col1,col2,col3)
VALUES (10,15,20)
,(1,2,3)
,(4,5,6)
,(10,0,0)
,(20,0,0);
Comparing using GREATEST() (Less verbose, but performance cost likely)
SELECT *,GREATEST(col1,col2,col3)
FROM tbl_test
WHERE GREATEST(col1,col2,col3) >= 10;
Performance Optimized Version (More verbose, but improved performance)
For performance reasons, I'd generally recommend separate queries instead of multiple OR statements. This allows database engine to use optimal indexes (should they exist)
SELECT * FROM tbl_test WHERE col1 >=10
UNION
SELECT * FROM tbl_test WHERE col2 >=10
UNION
SELECT * FROM tbl_test WHERE col3 >=10;

Copy field from one table to another with REGEXP_REPLACE

Before running a REGEXP_REPLACE on a big table, I want to preview the results, so I want to copy the 'before' and 'after' of the modified field to another table so I can audit.
What's the best way to do this?
Something like
INSERT INTO table2 (before, after)
SELECT field1, REGEXP_REPLACE(field1,'foo','bar')
FROM table1
WHERE condition
(MariaDB)
If this were my project I'd do these things.
First. Just do this and eyeball the results.
SELECT COUNT(*), field1, REGEXP_REPLACE(field1,'foo','bar')
FROM table1
WHERE field1 <> REGEXP_REPLACE(field1,'foo','bar')
GROUP BY field1, REGEXP_REPLACE(field1,'foo','bar')
ORDER BY COUNT(*), field1
That will show you the least frequent values first so you can see the one-off problems caused by your replace first. No need to create a table.
Second, I'd eyeball the values that DIDN'T change with this, changing the WHERE clause from <> to =.
SELECT COUNT(*), field1
FROM table1
WHERE field1 = REGEXP_REPLACE(field1,'foo','bar')
GROUP BY field1
ORDER BY COUNT(*), field1
Maybe some stuff didn't change that should have.
Edit SQL can get a little verbose. If you're fiddling around with some complex conversion functions you might try creating a view. Something like this:
CREATE OR REPLACE VIEW testview AS
SELECT field1,
REGEXP_REPLACE(field1,'foo','bar') changed
FROM table1;
Then you can do
SELECT COUNT(*), field1, changed
FROM testview
WHERE field1 <> changed
GROUP BY field1, changed
ORDER BY COUNT(*), field1;
And similar queries. If you must change your replace function, you can edit the view definition and do the CREATE OR REPLACE again.

MySQL insert into (conditionally selected table) in single statement

My dbm knowledge is still pretty limited, so I am not sure how to approach/solve this problem. I want to INSERT INTO one of two tables, say, table1 and table2, but I don't know which table until after a SELECT subquery. Something like this:
INSERT INTO (SELECT tblname) SELECT *, IF(somecondition, 'table1', 'table2') as tblname FROM `anothertable` WHERE id = 'someid'
I tried this as a test:
INSERT INTO (SELECT tblname) SELECT *, 'table1' as tblname FROM `anothertable` WHERE id = 'someid'
But that didn't work.
I know I can use subqueries in SELECT statements (so useful!), and that I can technically achieve what I want with NOT EXISTS in 2 statements, and I know I cannot INSERT into two tables, and I know that using # user variables is unreliable within a statement (see docs). So, is there a way to achieve what I want, in a single statement?
you can do it with case statement.
SELECT CASE WHEN ( SELECT IF(somecondition, 'table1', 'table2') as tblname FROM `anothertable` = 'table1' )
THEN <QUERY A>
ELSE <QUERY B>
END

Using HAVING clause on function result in select

I'm troubled how to use HAVING clause avoiding function calling twice.
here is my qry:
select col1, col2, dbo.someFunction(param1, param2) as col3
from...
where ...
group ...
having dbo.someFunction(param1, param2) > 0
if I wrote
having col3 > 0
server sais: Invalid column name 'col3 '.
Is there a way to use HAVING in shown situation without calling function dbo.someFunction twice?
EDIT
my execution plan with having:
and without having (commented):
Select without function in select:
Are you sure it is calling it twice?
I get the same execution plan from the following two queries
select enumID
from docSVenum1
group by enumID
having COUNT(*) > 2000
select enumID, count(*) as ccount
from docSVenum1
group by enumID
having COUNT(*) > 2000
In order not to call the function twice but refer to the result that is returned in column col3 you'll need another SELECT statement around your query, like below.
SELECT col1,
col2,
col3
FROM
(SELECT col1,
col2,
dbo.someFunction(param1, param2) AS col3
FROM ...
WHERE... ) AS Result
GROUP BY ...
HAVING col3 > 0
You can't reference a column by its alias on the same "nesting level" of the SELECT, which is why you'll have to surround your initial result in another SELECT statement, from which you will be able to reference the column by its alias.

Union with a timediff statement in MySQL

Not sure I'm going about this correctly to begin with - I have two valid SQL select statements that I would like to run together.
The first is
SELECT * FROM mytable;
The second is
Select TIMEDIFF(time2,time1) as diff from mytable;
So I thought maybe
SELECT * FROM mytable UNION Select TIMEDIFF(time2,time1) as diff from mytable;
But of course, the second statement doesn't have the same number of columns because it isn't a separate table. Those of you awesome at this will be able to figure it out in no time, I am sure.
select TIMEDIFF(time2,time1) as diff, t.* from mytable t;
Is it what you want?