In sqlalchemy I am trying to union tables and then make alias with WHERE and ORDER_BY
something like
SELECT *
FROM (
SELECT [TABLE_ONE].[SOME_ID] AS [SOME_ID]
FROM [TABLE_ONE]
UNION
SELECT [TABLE_TWO].[SOME_ID] AS [SOME_ID]
FROM [TABLE_TWO]
) AS anon_1
WHERE ...
SQLAlchemy:
select_q = select([TABLE_ONE.c.SOME_ID], TABLE_ONE)
select_w = select([TABLE_TWO.c.SOME_ID], TABLE_TWO)
union_qw = union(select_q,select_w)
union_qw_aliased = aliased(union_qw)
s = select('*',union_qw_aliased)
but SQLAlchemy produces SQL code:
SELECT anon_1.[SOME_ID]
FROM (SELECT [TABLE_ONE].[SOME_ID] AS [SOME_ID]
FROM [TABLE_ONE] UNION SELECT [TABLE_TWO].[SOME_ID] AS [SOME_ID]
FROM [TABLE_TWO]) AS anon_1
WHERE SELECT [TABLE_ONE].[SOME_ID]
FROM [TABLE_ONE] UNION SELECT [TABLE_TWO].[SOME_ID]
FROM [TABLE_TWO]
Any help is appreciated
you're mis-using the second argument to "select()", which is actually the "whereclause" (though we encourage the use of the where() method these days). the FROM clause is usually implicit from the columns you're selecting. For your "select *", we can set an explicit FROM using select_from():
from sqlalchemy import *
m = MetaData()
t1 = Table('t1', m, Column('id', Integer))
t2 = Table('t2', m, Column('id', Integer))
select_q = select([t1])
select_w = select([t2])
union_qw = union(select_q, select_w)
union_qw_aliased = union_qw.alias()
s = select('*').select_from(union_qw_aliased)
print s
output:
SELECT *
FROM (SELECT t1.id AS id
FROM t1 UNION SELECT t2.id AS id
FROM t2) AS anon_1
to do more WHERE, add that using where() and do it against union_qw_aliased:
print s.where(union_qw_aliased.c.id == 5)
output:
SELECT *
FROM (SELECT t1.id AS id
FROM t1 UNION SELECT t2.id AS id
FROM t2) AS anon_1
WHERE anon_1.id = :id_1
Related
I try to use a field from joined table "glpi_items_tickets" into a subquery like this :
SELECT
NAME
FROM
(
SELECT
NAME
FROM glpi_computers
WHERE id = git.items_id
) AS t1
UNION
(
SELECT
NAME
FROM glpi_monitors
WHERE id = git.items_id
)
UNION
(
SELECT
NAME
FROM glpi_networkequipments
WHERE id = git.items_id
)
UNION
(
SELECT
NAME
FROM glpi_printers
WHERE id = git.items_id
)
) AS aliasIT
but i have an error of type : "#1054 - Unknown Column 'git.items_id' in where clause"
The entire request :
SELECT
gt.id,
(
SELECT
NAME
FROM
(
SELECT
NAME
FROM glpi_computers
WHERE id = git.items_id
) AS t1
UNION
(
SELECT
NAME
FROM glpi_monitors
WHERE id = git.items_id
)
UNION
(
SELECT
NAME
FROM glpi_networkequipments
WHERE id = git.items_id
)
UNION
(
SELECT
NAME
FROM glpi_printers
WHERE id = git.items_id
)
) AS aliasIT
FROM glpi_tickets gt
INNER JOIN glpi_items_tickets git
ON gt.id = git.tickets_id;
Do you have a solution for used the field "glpi_items_tickets.items_id" into my subqueries?
SELECT ...
FROM
glpi_tickets gt
INNER JOIN glpi_items_tickets git
ON git.tickets_id = gt.id;
INNER JOIN
(
SELECT NAME, id FROM glpi_computers
UNION
SELECT NAME, id FROM glpi_monitors
UNION
SELECT NAME, id FROM glpi_networkequipments
UNION
SELECT NAME, id FROM glpi_printers
) g
ON g.id = git.items_id
Use the full table name instead of the alias.
Replace every git.items_id with glpi_items_tickets.items_id.
The alias does not exist during the compilation of the subquery, since the outer query (where you set your alias) can not be compiled until the inner querys are considered valid.
I have a table into MySQL DB (version 5.1.x), with the name table. Its columns are:
id, double_col_index1, double_col_index2, flag, col_index_1, a_date_col, col_index_2, col_index_3 with the following indexes:
a single index on double_col_index1 and double_col_index2
an index on col_index_1
an index on col_index_2
an index on col_index_3
Now, I have the following query:
UPDATE `table` t1 INNER JOIN
(SELECT t2.id FROM `table` t2
WHERE t2.double_col_index1 = 'fake_value1'
AND t2.double_col_index2 = 'fake_value2'
AND flag = 'true'
AND (col_index_1 = '' OR a_date_col < '1920-11-10 00:00:00')
AND
(SELECT count(t3.id) FROM `table` t3
WHERE t3.double_col_index1 = 'fake_value1'
AND t3.double_col_index2 = 'fake_value2'
AND t3.col_index_2 = t2.col_index_2
AND t3.col_index_3 = 'fake_col_index_3_1') > 0
AND
(SELECT count(t4.id) FROM `table` t4
WHERE t4.double_col_index1 = 'fake_value1'
AND t4.double_col_index2 = 'fake_value2'
AND t4.col_index_2 = t2.col_index_2
AND t4.col_index_3 = 'fake_col_index_3_2') > 0) tbl
ON t1.id = tbl.id SET col_index_1 = 'fake_value';
Question: I would need to improve this query, to give a better performance if possible. Would anyone have any suggestions on this?
One idea would be to use instead of INNER JOIN an t1.id in (.... What is your advice on this?
Basic idea of the join would be to do it as follows.
UPDATE `table` t1
INNER JOIN
(
SELECT t2.id
FROM `table` t2
INNER JOIN
(
SELECT DISTINCT col_index_2
FROM `table`
WHERE double_col_index1 = 'fake_value1'
AND double_col_index2 = 'fake_value2'
AND col_index_3 = 'fake_col_index_3_1'
) t3
ON t3.col_index_2 = t2.col_index_2
INNER JOIN
(
SELECT DISTINCT col_index_2
FROM `table`
WHERE double_col_index1 = 'fake_value1'
AND double_col_index2 = 'fake_value2'
AND col_index_3 = 'fake_col_index_3_2'
) t4
ON t4.col_index_2 = t2.col_index_2
WHERE t2.double_col_index1 = 'fake_value1'
AND t2.double_col_index2 = 'fake_value2'
AND flag = 'true'
AND (col_index_1 = '' OR a_date_col < '1920-11-10 00:00:00')
) tbl
ON t1.id = tbl.id
SET col_index_1 = 'fake_value';
This may be quite a bit quicker but will depend on many factors. MySQL will not use indexes for joining against the sub queries.
However there is a big issue with this (and your existing query) in MySQL
http://dev.mysql.com/doc/refman/5.7/en/update.html
Currently, you cannot update a table and select from the same table in a subquery.
There is a way round this, by doing a query on the sub query
I currently have such a query:
SELECT
sec_to_time(avg(t1.sessiontime)) as aloc,
count(*) as calls
FROM
table1 AS t1
inner join
table2 as t2 ON t1.destination = t2.prefix
WHERE
t1.card_id = '101'
AND
t1.terminatecauseid = 1
group by t1.destination
Example result:
The 'calls' data is bound to 't1.terminatecauseid = 1' (meaning only answered calls)
I'd like to have a percentage of answered calles from the total calls made.
the same query without the condition (t1.terminatecauseid = 1) will give me the total calls made.
I'd like to know what is the best way to add another column called 'Average Success Rate' that will do:
total-calls*successful-calls/100
Is a subquery what's needed here? or a brand new and different query?
SELECT
sec_to_time(avg(t1.sessiontime)) as aloc,
sum(t1.terminatecauseid = 1) * 100 / count(*) as Average_Success_Rate,
sum(t1.terminatecauseid = 1) as calls
FROM
table1 AS t1
inner join
table2 as t2 ON t1.destination = t2.prefix
WHERE
t1.card_id = '101'
group by t1.destination
I have the following query:
select
tt.ItemOrder, tt.DisplayVal as Task, tt.Responsible as ResParty,
tt.DaysDue,
ActualDate = (select convert(varchar(10), cnfmdate, 101) from ProSer where PId = #PID), PDate = #PDate
from
tblTimeline tt
where
tt.ID = 1
What I need to do is to put it in a view such that I can call the view simply using the PID.
I came up with the following and used the cross join:
create view view1 as
select
ps.PID, tt.ID, tt.ItemOrder, tt.DisplayVal as Task,
tt.Responsible as ResParty, tt.DaysDue,
ps.cnfmdate As ActualDate, ProgStartDate as ProgramDate
from
tblTimeline tt
cross join
ProSer ps
where
tt.ID = 1 and ps.cancelled = 0
Notice now, I can do the following
select *
from view1
where PID = '34343'
and then I can retrieve it from the view.
Now, I am not sure how to do similiarly with the following in which case I need to put it in a cross join similarly to how I did above.
Notice how actual date is somehat more involved. I need to use the cross table similarly to how I did it above but not as you can see, it is somewhat more involved.
(notice for this part, I will simly join to the view1 that I have above with UNION
select
tt.ItemOrder, tt.DisplayVal as Task, tt.Responsible as ResParty,
ActualDate = (
CASE
WHEN
NOT EXISTS(SELECT * FROM Spls WHERE RequestRcvd = 1 AND PID = #PID)
THEN
'N/A'
WHEN EXISTS (SELECT * FROM spls WHERE RequestRcvd = 1 AND RequestRcvdDate IS NOT NULL)
THEN
(SELECT CONVERT(VARCHAR(10),MAX(RequestRcvdDate),101) from spls WHERE RequestRcvd = 1 AND PID = #PID)
END
)
from
tblTimeline tt
where
tt.ID = 9
I need to know how I can create this in a cross join (which will be inside of a view) such that I can do the following similarly to how I did the above one
select *
from view1
where PID = '34343'
and then I can retrieve it from the view.
There might be a way to simplify the query, but the following should work:
select p.pid, tt.ItemOrder, tt.DisplayVal as Task,
tt.Responsible as ResParty,
ActualDate = (CASE WHEN NOT EXISTS(SELECT * FROM Spls WHERE RequestRcvd = 1 AND spls.PID = p.PID)
THEN 'N/A'
WHEN EXISTS (SELECT * FROM spls WHERE RequestRcvd = 1 AND RequestRcvdDate IS NOT NULL)
THEN (SELECT CONVERT(VARCHAR(10),MAX(RequestRcvdDate),101) from spls WHERE RequestRcvd = 1 AND spls.PID = p.PID)
END)
from tblTimeline tt cross join
poser p
where tt.ID = 9
All I did was add the cross join to poser and replace #PID with p.pid. The results is a subquery that contains a reference to a table at an outer level. Such a subquery is called a correlated subquery.
I'm trying to run this query:
UPDATE anothertable
INNER JOIN (SELECT *,
LEAST(table1.from_price, table2.from_price, table3.from_price) AS cheapestPrice
FROM (SELECT * FROM table1 v WHERE hotelid >= 1
UNION
SELECT * FROM table2 c WHERE hotelid >= 1
UNION
SELECT * FROM table3 k WHERE hotelid >= 1) AS temp
GROUP BY temp.hotelid, temp.country) AS i ON anothertable.id = i.hotelid
AND anothertable.country = i.country
SET price = i.cheapestPrice,
op = i.to
However I cannot get the LEAST function to get access to a field called "from_price".
Ideas?
You should use Min instead of Least:
Update anothertable
Join (
Select hotelid, country, to
, Min(from_price) AS cheapestPrice
From (
Select hotelid, country, from_price, to
From table1 v
Where hotelid >= 1
Union
Select hotelid, country, from_price, to
From table2 c
Where hotelid >= 1
Union
Select hotelid, country, from_price, to
From table3 k
Where hotelid >= 1
) AS temp
Group By temp.hotelid, temp.country, temp.to
) As i
On anothertable.id = i.hotelid
And anothertable.country = i.country
Set price = i.cheapestPrice
, op = i.to
Edit
As pointed out in comments, I omitted the to column from the inner temp query. However, it occurs to me that it isn't clear how to should be included because you are using an awful feature of MySQL with respect to declaring the Group By columns. I'm assuming that you need to include to in the Group By however if that is not the case, you should be explicit about what aggregate function it should use on the to column.
Here's an alternate where I use Min on the to column:
Update anothertable
Join (
Select temp.hotelid, temp.country
, Min(temp.to) As to
, Min(temp.from_price) AS cheapestPrice
From (
Select v.hotelid, v.country, v.from_price, v.to
From table1 v
Where hotelid >= 1
Union
Select c.hotelid, c.country, c.from_price, c.to
From table2 c
Where hotelid >= 1
Union
Select k.hotelid, k.country, k.from_price, k.to
From table3 k
Where hotelid >= 1
) AS temp
Group By temp.hotelid, temp.country
) As i
On anothertable.id = i.hotelid
And anothertable.country = i.country
Set price = i.cheapestPrice
, op = i.to