shorthand notation for query in mysql - mysql

Is there a method to give a shorthand notation to a query?
ex.
Q1 = (select * from tablename2)
Q2 = (select * from tablename2)
select name from Q1;
select name from Q2;
I am aware of views but I do not intend to use them.

Yes. Create a view.
CREATE VIEW Q1 AS (
SELECT
name,
id,
othercol
FROM tablename1
);
/* Works with a WHERE clause too */
CREATE VIEW Q2 AS (
SELECT
name,
id,
othercol
FROM tablename2
WHERE othercol = 'some limitation'
);
SELECT name FROM Q1;
/* aggregates work too */
SELECT name, COUNT(*) AS numrows FROM Q2 GROUP BY name;
Note: It is not recommended to SELECT * in a view (or really anywhere in production code). Always be explicit about the columns in the select list so their order will be deterministic.
Alternatively, create a temporary table using the CREATE TEMPORARY TABLE ... SELECT syntax.
CREATE TEMPORARY TABLE Q1
SELECT name, id, othercol FROM tablename1;
/* select from it */
SELECT name FROM Q1 WHERE id IN (1,2,3,4,5)
/* When done, drop it. Otherwise, it will be dropped when the client connection terminates. */
DROP TABLE Q1;

I think you're talking about views. check out the docs for them.

A view is similar to what you're looking for.
But a "view" is less a notational convenience than an "alias" or "facade" for other queries or updates. A good metaphore is "a view is a virtual table". In MSSQL, "views" can also be an effective way to enhance security.
Here is a good article on the subject:
http://msdn.microsoft.com/en-us/library/aa214068%28v=sql.80%29.aspx

Related

MySQL performance JSON functions

We faced with unpredictable duration of executing our code. The same query can take less than a second, or more than a minute. It looks like our attempt to use MySQL JSON_ functions probably was not a good idea.
select p.pk,
p.name,
... /* fields from primary table */
(SELECT JSON_ARRAYAGG(CODE)
FROM (SELECT region.region_pk AS CODE
FROM program_region region
WHERE region.program_pk = p.pk) AS a)
AS region_codes,
(SELECT JSON_ARRAYAGG(CODE)
FROM (SELECT affiliate.affiliate_pk AS CODE
FROM program_affiliate affiliate
WHERE affiliate.program_pk = p.pk) AS a) AS affiliate_codes,
(SELECT JSON_ARRAYAGG(user_id)
FROM (SELECT DISTINCT user_id
FROM (SELECT role.user_id
FROM program_role role
WHERE role.program_pk = p.pk
UNION ALL
SELECT p.created_by) AS us) AS a) AS user_ids
from program p;
Structure:
program:
pk bigint,
name varchar ...
program_affiliate and other child tables
pk bigint,
program_pk bigint /* FK with index */
code varchar(20)
...
We checked another queries works as usual but only new ones has these issues.
Does anybody else faced with performance issues with JSON functions before? Any recommendations?

create a view from two tables in athena query

Basically my use case is that I am creating a view in athena but i want to select the data from two tables depending on the date (snapshot_date) which is given by a column in the tables. How to do it? I am not finding the syntax for that
SELECT
baseline_year
, marketplace
, locale
, snapshot_time
, ...
FROM
table1
I want to achieve something like if snapshot time is less than 2022-05-01, then use table 2 otherwise use table 1.
Can we any kind of conditioning in FROM? I have explored that we can use CASE_WHEN for performing conditions on columns, but not sure that can be used in FROM?
If I am not mistaken, you meant to use table2 if the snapshot_time is earlier than 2022-05-01 and use table1 if the snapshot_time is greater than or equal to 2022-05-01 REGARDLESS of what shapshot_time those two tables have.
SELECT ... FROM table1 where date(snapshot_time)>= '2022-05-01'
union
SELECT ... FROM table2 where date(snapshot_time) < '2022-05-01' ;
You can proceed with a parametrized view, try to create a function:
CREATE FUNCTION func() RETURNS DATE
RETURN #var;
Then create the view :
CREATE VIEW view1 AS
SELECT
T1.baseline_year
, T1.marketplace
, T1.locale
, T1.snapshot_time
, ...
FROM table1 AS T1
WHERE DATE(T1.snapshot_time) >= func()
UNION
SELECT
T2...,
..
FROM
table1 AS T2
WHERE DATE(T2.snapshot_time) <= func()

SQL - Nested query optimization

How can I optimize this query SQL?
CREATE TABLE table1 AS
SELECT * FROM temp
WHERE Birth_Place IN
(SELECT c.DES_COM
FROM tableCom AS c
WHERE c.COD_PROV IS NULL)
ORDER BY Cod, Birth_Date
I think that the problem is the IN clause
First of all it's not quite valid SQL, since you are selecting and sorting by columns that are not part of the group. What you want to do is called "select top N in group", check out Select first row in each GROUP BY group?
Your query doesn't make sense, because you have SELECT * with GROUP BY. Ignoring that, I would recommend writing the query as:
SELECT t.*
FROM temp t
WHERE EXISTS (SELECT 1
FROM tableCom c
WHERE t.Birth_Place = c.DES_COM AND
c.COD_PROV IS NULL
)
ORDER BY Cod, Birth_Date;
For this, I recommend an index on tableCom(desc_com, cod_prov). Your database might also be able to use an an index on temp(cod, birth_date, birthplace).

Table is specified twice, both as a target for 'UPDATE' and as a separate source for data in mysql

I have below query in mysql where I want to check if branch id and year of finance type from branch_master are equal with branch id and year of manager then update status in manager table against branch id in manager
UPDATE manager as m1
SET m1.status = 'Y'
WHERE m1.branch_id IN (
SELECT m2.branch_id FROM manager as m2
WHERE (m2.branch_id,m2.year) IN (
(
SELECT DISTINCT branch_id,year
FROM `branch_master`
WHERE type = 'finance'
)
)
)
but getting error
Table 'm1' is specified twice, both as a target for 'UPDATE' and as a
separate source for data
This is a typical MySQL thing and can usually be circumvented by selecting from the table derived, i.e. instead of
FROM manager AS m2
use
FROM (select * from manager) AS m2
The complete statement:
UPDATE manager
SET status = 'Y'
WHERE branch_id IN
(
select branch_id
FROM (select * from manager) AS m2
WHERE (branch_id, year) IN
(
SELECT branch_id, year
FROM branch_master
WHERE type = 'finance'
)
);
The correct answer is in this SO post.
The problem with here accepted answer is - as was already mentioned multiple times - creating a full copy of the whole table. This is way far from optimal and the most space complex one. The idea is to materialize the subset of data used for update only, so in your case it would be like this:
UPDATE manager as m1
SET m1.status = 'Y'
WHERE m1.branch_id IN (
SELECT * FROM(
SELECT m2.branch_id FROM manager as m2
WHERE (m2.branch_id,m2.year) IN (
SELECT DISTINCT branch_id,year
FROM `branch_master`
WHERE type = 'finance')
) t
)
Basically you just encapsulate your previous source for data query inside of
SELECT * FROM (...) t
Try to use the EXISTS operator:
UPDATE manager as m1
SET m1.status = 'Y'
WHERE EXISTS (SELECT 1
FROM (SELECT m2.branch_id
FROM branch_master AS bm
JOIN manager AS m2
WHERE bm.type = 'finance' AND
bm.branch_id = m2.branch_id AND
bm.year = m2.year) AS t
WHERE t.branch_id = m1.branch_id);
Note: The query uses an additional nesting level, as proposed by #Thorsten, as a means to circumvent the Table is specified twice error.
Demo here
Try :::
UPDATE manager as m1
SET m1.status = 'Y'
WHERE m1.branch_id IN (
(SELECT DISTINCT branch_id
FROM branch_master
WHERE type = 'finance'))
AND m1.year IN ((SELECT DISTINCT year
FROM branch_master
WHERE type = 'finance'))
The problem I had with the accepted answer is that create a copy of the whole table, and for me wasn't an option, I tried to execute it but after several hours I had to cancel it.
A very fast way if you have a huge amount of data is create a temporary table:
Create TMP table
CREATE TEMPORARY TABLE tmp_manager
(branch_id bigint auto_increment primary key,
year datetime null);
Populate TMP table
insert into tmp_manager (branch_id, year)
select branch_id, year
from manager;
Update with join
UPDATE manager as m, tmp_manager as tmp_m
inner JOIN manager as man on tmp_m.branch_id = man.branch_id
SET status = 'Y'
WHERE m.branch_id = tmp_m.branch_id and m.year = tmp_m.year and m.type = 'finance';
This is by far the fastest way:
UPDATE manager m
INNER JOIN branch_master b on m.branch_id=b.branch_id AND m.year=b.year
SET m.status='Y'
WHERE b.type='finance'
Note that if it is a 1:n relationship the SET command will be run more than once. In this case that is no problem. But if you have something like "SET price=price+5" you cannot use this construction.
Maybe not a solution, but some thoughts about why it doesn't work in the first place:
Reading data from a table and also writing data into that same table is somewhat an ill-defined task. In what order should the data be read and written? Should newly written data be considered when reading it back from the same table? MySQL refusing to execute this isn't just because of a limitation, it's because it's not a well-defined task.
The solutions involving SELECT ... FROM (SELECT * FROM table) AS tmp just dump the entire content of a table into a temporary table, which can then be used in any further outer queries, like for example an update query. This forces the order of operations to be: Select everything first into a temporary table and then use that data (instead of the data from the original table) to do the updates.
However if the table involved is large, then this temporary copying is going to be incredibly slow. No indexes will ever speed up SELECT * FROM table.
I might have a slow day today... but isn't the original query identical to this one, which souldn't have any problems?
UPDATE manager as m1
SET m1.status = 'Y'
WHERE (m1.branch_id, m1.year) IN (
SELECT DISTINCT branch_id,year
FROM `branch_master`
WHERE type = 'finance'
)

What would be an instance where MultiStatement Table Valued Function(MTVF) is needed over an Inline Table Valued Function(ITVF) in SQL?

I was able to write two SQL queries, first one is an Inline Table Valued Function(ITVF) and the latter is a Multistatement Table Valued Function(MTVF) for the same task which is quering the worktime of certain employees.
-------------- Inline Table Valued Function (ITVF) ---------------------
CREATE FUNCTION fn_ITVF_GetWorkTimes()
RETURNS TABLE
AS RETURN( SELECT E.ID, E.Name, E.DepartmentID, R.TotalTime
FROM tblEmployee E
INNER JOIN
( SELECT T.Id, CAST(DATEDIFF(MINUTE,StartTime,EndTime)/60.0 as DECIMAL(18,2)) AS 'TotalTime'
FROM tblTimeRecord T) AS R
ON E.ID = R.Id )
SELECT * FROM fn_ITVF_GetWorkTimes();
--------------- Multi-Statement Table Valued Functions (MTVF) -------------------
CREATE FUNCTION fn_MTVF_GetEmployeeTimes()
RETURNS #Table1 TABLE(Id INT,Name NVARCHAR(50),DepartmentID INT,TimeWork DECIMAL(18,2))
AS
BEGIN
INSERT INTO #Table1
SELECT E.Id, E.Name, E.DepartmentId, R.TotalTime
FROM tblEmployee AS E
INNER JOIN
(SELECT T.ID, CAST(DATEDIFF(MINUTE,T.StartTime,T.EndTime)/60.0 as DECIMAL (18,2)) AS 'TotalTime'
FROM tblTimeRecord AS T) AS R
ON E.Id=R.ID
RETURN
END
SELECT * FROM dbo.fn_MTVF_GetEmployeeTimes();
I am aware that few questions have been raised on this topic earlier, but still i could not find out a scenario which only a MultiStatement Table Valued Function can be applied and is there a clear reason why an ITVF cannot be applied for such a scenario ? According to my research it has been advised to use ITVF all the time if it is possible and it seems it is more efficient than MTVF as well. If it is true why would anyone tend to use MTVF ? Clear explantion with examples would be highly appreciated.
Apart from the syntax the main limitation between IVTF and MVTF is that IVTF can only have A Single Select Statement same as views.
Whereas on the other hand MVTF can have a more complex logic inside them. IF/Else blocks etc.
Some say IVTF can be seen as Parameterised Views and MVTF can be seen as Stored procedures you can select from.