Using many tables related with left outer joins in my queries,
I wonder if there is any way of getting easily the query result as a basic array, the type one can expect in phpmyadmin for example (I don't mean the layout).
Given 3 tables, all tables being mapped, I presently only get the result of the first table as an object, from which I have to test row after row if there is any results for table2, and so on for table 3 :
list_res_table1 = DBSession.query(table1).outerjoin(table2).outerjoin(table3).all()
for res_table1 in list_res_table1:
if res_table1.relationship_to_table2:
list_res_table2 = res_table1.relationship_to_table2
for res_table2 in list_res_table2:
if res_table2.relationship_to_table3:
etc.
It would be great to get a list of objects directly accessible like :
((table1, table2, None) #=> no result for table3
(table1, None, None) #=> no result for table2
(table1, table2, table3)) #=> results for all tables
you can (and certainly should) query like this directly:
list_res_table1 = DBSession.query(table1, table2, table3).outerjoin(table2).outerjoin(table3).all()
the joining will look at the leftmost table first. if you need more specificity, you can add in select_from() as well as explicit ON clauses:
list_res_table1 = DBSession.query(table1, table2, table3).\
select_from(table1).\
outerjoin(table2, table2.c.id==table1.c.t2id).\
outerjoin(table3, table2.c.t3id==table3.c.id).all()
Related
I have two tables in my mysql database. The first table has the columns "id" and "text", the second table has the columns "text_id" and "keyword" which contais a single keyword belonging to the text with the given ID. Column "text_id" of the second table is always equal to the according id in table 1. Table two can contain multiple rows with the same "text_id" and different "keyword"s.
I want to filter those articles for their linked keywords. For example SELECT * FROM table1 INNER JOIN table2 ON table2.text_id = table1.id WHERE table1.id = "1" contains a list with 5 different keywords. Now I want to only recieve the data if two (or more) given keywords are in any of those rows.
However WHERE table2.keyword ="XXX" AND table2.keyword = "YYY" obviously does not return anything because one cell cannot be equal to two different values. On the other hand WHERE table2.keyword ="XXX" OR table2.keyword = "YYY" returns the data where only one and not neccessarily both values are included.
Is there any way to achieve this via a mysql query? Or do I have to make different queries for the desired keywords and compare their returned IDs later on?
As far as I know you need to do one of the two things:
JOIN table2 two (or more) times, once for every keyword
SELECT *
FROM table1
INNER JOIN table2 AS xxx ON table1.id = xxx.text_id
INNER JOIN table2 yyy ON table1.id = yyy.text_id
WHERE xxx.keyword = "XXX"
AND yyy.keyword = "YYY"
OR use aggregation function GROUP_CONCAT, and search in the GROUPED field using HAVING. However this approach has two major drawbacks - GROUP_CONCAT field length is limited and using HAVING is slower than using WHERE (it searches "later" for the requested value in execution of the query).
I'm trying to see if my understanding of JOINs is correct.
For the following query:
SELECT * FROM tableA
join tableB on tableA.someId = tableB.someId
join tableC on tableA.someId = tableC.someId;
Does the RDMS basically execute similar pseudocode as follows:
List tempResults
for each A_record in tableA
for each B_record in tableB
if (A_record.someId = B_record.someId)
tempResults.add(A_record)
List results
for each Temp_Record in tempResults
for each C_record in tableC
if (Temp_record.someId = C_record.someId)
results.add(C_record)
return results;
So basically the more records with the same someId tableA has with tableB and tableC, the more records the RDMS have the scan? If all 3 tables have records with same someId, then essentially a full table scan is done on all 3 tables?
Is my understanding correct?
Each vendor's query processor is of course written (coded) slightly differently, but they probably share many common techniques. Implementing a join can be done in a variety of ways, and which one is chosen, in any vendor's implementation, will be dependent on the specific situation, but factors that will be considered include whether the data is already sorted by the join attribute, the relative number of records in each table (a join between 20 records in one set of data with a million records in the other will be done differently than one where each set of records is of comparable size). I do not know the internals for MySQL, but for SQL server, there are three different join techniques, a Merge Join, a Loop Join, and a Hash Join. Take a look at this.
I have a join, I would like it to collect the name of two items by joining the item table on the item id for two different item ids. For example:
SELECT first_item_name, second_item_name FROM items JOIN order_table ON ...
and here is where I am stuck - what I effectively need to do is two joins on one table, the first to select the first item's name:
ON first_item_id = first_id
and then go back and select the second item's name with another join:
ON second_item_id = second_id
my question is can this be done from within a single join?
Thank you.
In a word; No.
The thing to bear in mind is that the
On value = value
clause must evaluate to TRUE for each tuple (think of a tuple as in effect record but a record created by the join) created by the join. So if tableA.col1 = tableB.col1 is true for the first tuple than it cannot at the same time also be true for tableA.col1 = tableB.col1 for the second tuple . And here is the wrinkle; in both cases tableA.col1 = tableB.col1 but only for each tuple individually, in a way you are asking can I have tuple1 and tuple2 at the same time.
And do not be concerned about joining more than once to the same table. It is not wrong, not inherently going to cause bad performance or for any other reason to be avoided.
I am working in mysql with queries, but I am new to this. I am joining 5 tables where each table has an identifier and one table is the master. Each related table may have more than one associated record to the master table. I am attempting to join these tables but I can't seem to get rid of the duplicated data.
I want all of the related records to be displayed, but I don't want the data in the master table to display for all results in the related tables. I have tried so many different methods but nothing has worked. Currently I have 4 queries that work for the separate tables, but I have not successfully joined them to have the results display the multiple records in the related table but just one record from the master table.
Here are my individual queries that work:
SELECT
GovernmaxAdditionsExtract.AdditionDescr,
GovernmaxAdditionsExtract.BaseArea,
GovernmaxAdditionsExtract.Value
FROM
GovernmaxExtract
INNER JOIN GovernmaxAdditionsExtract
ON GovernmaxExtract.mpropertyNumber = GovernmaxAdditionsExtract.PropertyNumber
WHERE (((GovernmaxExtract.mpropertyNumber)="xxx-xxx-xx-xxx"));
SELECT
GovernmaxExtract.mpropertyNumber,
GovernmaxDwellingExtract.CardNumber,
GovernmaxDwellingExtract.MainBuildingType,
GovernmaxDwellingExtract.BaseArea
FROM
GovernmaxExtract INNER JOIN
GovernmaxDwellingExtract ON GovernmaxExtract.mpropertyNumber = GovernmaxDwellingExtract.PropertyNumber
WHERE (((GovernmaxExtract.mpropertyNumber)="xxx-xxx-xx-xxx"));
Using these sub queries, I tried to put together 2 of the tables, but now I am getting all records back and it is not reading my input parameter:
SELECT GE.mpropertynumber
FROM
GovernmaxExtract AS GE,
(SELECT
GovernmaxAdditionsExtract.AdditionDescr,
GovernmaxAdditionsExtract.BaseArea,
GovernmaxAdditionsExtract.Value
FROM GovernmaxExtract INNER JOIN
GovernmaxAdditionsExtract ON
governmaxextract.mpropertyNumber = GovernmaxAdditionsExtract.PropertyNumber) AS AE
WHERE GE.mpropertynumber = 'xxx-xxx-xx-xxx'
I tried nested queries, lots of different joins, and I am just not able to wrap my head around this. I am pretty sure I want to do a nested query since I want the main data from the Governmax table to display once with the main data and all records with all info for the associated tables. Maybe I am going about it all wrong.
Our original code was:
SELECT
ge.*,
gde.*,
gfe.*,
gae.*,
goie.*
FROM governmaxextract AS ge
LEFT JOIN governmaxdwellingextract AS gde
ON ge.mpropertyNumber = gde.PropertyNumber
LEFT JOIN governmaxfeaturesextract AS gfe
ON gde.PropertyNumber = gfe.PropertyNumber
LEFT JOIN governmaxadditionsextract AS gae
ON gde.PropertyNumber = gae.PropertyNumber
RIGHT JOIN governmaxotherimprovementsextract AS goie
ON gde.PropertyNumber = goie.PropertyNumber
WHERE ge.mpropertyNumber = '$codeword'
ORDER BY goie.CardNumber
But this gives multiple rows from the master table for each record in the associated tables. I thought about concatenate, but I need the data from the associated tables to be displayed individually. Not sure what to try next. Any help is much appreciated.
Sorry, and there is no way to do that like you want. JOIN's can't do that.
I suggest to keep solution with separate queries.
Btw - You could play with UNION operator,
http://en.wikipedia.org/wiki/Union_(SQL)#UNION_operator
P.s.
You could extract main data separately, then extract data from related tables at once using UNION. With UNIOM it will give one result row per each row in related table.
In order to join an two of the Detail tables together without generating duplicate rows, you will have to perform the following operation on each one:
Group on the foreign key to the Master table, and aggregate all other columns being projected onto the join.
Numeric columns are commonly aggregated with SUM(), COUNT(), MAX(), and MIN(). MAX() and MIN() are also applicable to character data. A PIVOT operation is also sometimes useful as an aggregation operator for this type of circumstance.
Once you have two of the Detail tables grouped and aggregated in this way, they will join without duplicates. Additional Detail tables can be added to the join by first grouping and aggregating them also, in the same fashion.
With a single query, I need to get a list of ALL objects A and an additional column returning "1" when there is an association to an Object C in Table B, or returning "0" when there is no associaton to an Object C in Table B.
Table A holds all objects A
Table B holds all objects A associated to another object C.
I know the ID of object C.
Currently I am using a Query with LEFT JOIN and two conditions with AND in the JOIN.
For the return value column I am using "(TableB.id IS NOT NULL) as associated".
Table A will likely hold only between dozens up to a hundred records.
Table B will likely hold between thousands to hundreds of thousands records.
Table C will likely hold between thousands to hundreds of thousands records.
TableA.id is index
TableB.tablea_id is index
TableB.id is index
TableB.tablec_id is index
TableC.id is index
My query currently looks like this:
SELECT TableA.name, TableA.code, (TableB.id IS NOT NULL) AS associated
FROM TableA
LEFT JOIN TableB ON TableA.id=TableB.tablea_id AND TableB.tablec_id = $input
Is there any performance concern about the method I use for the SQL query or a better way of achieving the desired result ?
Your query looks fine as far as I can see.
However, you should keep in mind that conditions on join should be for matching foreign keys. Following this practice at least makes your queries more readable and maintainable.