what does query(class1).join(class2) do? - sqlalchemy

I created a User and Address class and populated it with some data: 3 users, 6 addresses, first user has 1 address, second user has 2 addresses, and the third user has 3 addresses.
If I do
q = session.query(User).join(Address).all()
I see the generated SQL as
SELECT user... FROM users JOIN addresses ON users.id = addresses.user_id;
as expected. However, I expected 6 rows when I print q but I only get 3, namely the 3 users.
If I issue out the SQL inside sqlite3, I get my 6 rows.
So, what does query(class1).join(class2) do? Looks like an inner join but it's not.

The fact that you have also JOIN on Address will only change the WHERE clause, so it will not return those Users who do not have any addresses. And, even those the SQL query returns 6 rows, since you asked [query(User)] only for Users, it will return just 3 User objects.
Shall you want to get all combinations of (User, Address) tuples, you should add Address to your query(...) part as well:
q = session.query(User, Address).join(Address).all()
for user, address in q:
print user, address
which will return all 6 rows.
If you also wish to return those Users who do not have any address, use outerjoin instead of join.

Related

Querying multiple SQL tables

I'm having trouble understanding joins and subqueries and when to use each. I'm sure that one of them is appropriate here.
I have a table ("owners") of (to keep things simple) unit numbers, names and email addresses.
I have another table ("widgets") of unit numbers and the number of widgets assigned to each unit. Each unit has 0, 1 or 2 widgets.
I need to send an email to each unit depending on whether they have 0, 1 or 2 widgets. In other words (and in plain English, not even remotely an attempt at semi-correct SQL):
select numwidgets from widgets where unit=x
then where owners.unit = widgets.unit
select unit, name, email
The data that I need to pass to my script will look like this:
unit name email widgets
1 Bob Smith bob#example.com 2
I can visualise in my mind the data that I need, but it's extracting it from two different tables that is the problem. The "owners" table is a permanent table, and the "widgets" table is a temporary one for tracking a specific issue that is being addressed in the email I'm sending. I don't need help sending the email, just creating the SQL I need to use to extract the data (numwidgets, name, email) for one email.
Thanks.
EDIT:
Input data:
owners table:
unit, name, email
1,Bob Smith, bob#example.com
widgets table:
unit,widgets
1,2
try this, a inner join selects all rows from both tables as long as there is a match between the columns in both tables.
Subqueries (also known as inner queries or nested queries) are a tool for performing operations in multiple steps. For example, if you wanted to take the sums of several columns, then average all of those values, you’d need to do each aggregation in a distinct step.
select owners.unit, name, email, widgets.numwidgets
from owners
inner join widgets On owners.unit = widgets.unit
where owners.unit = x
For your case you need an inner join. To understand that you need to see the concept of keys which is pretty simple.
In your tables unitnumber is the common column in both tables. So a join has to be applied based on this column.
Subqueries are used when the output of one query is given as input to another query i.e to perform related operations
Select o.unit,o.name,o.email ,w.numwidgets from owners o inner join widgets w on o.unit=w.unit where w.unit=X
In above query pass X = 0,1,2 as per the result you want
Thanks
I think you want:
select o.*, w.widgets
from owners o
inner join widget w
on o.unit = w.unit
where o.unit = 123;

Joining multiple tables that return n results

I'm working on a JSON api. I'm aiming for speed, and making the least amount of queries possible by joining related data.
I can do joins. But I'm confused about something. How do I join multiple tables that return n number of records? For example, lets say I have the following tables:
- Users
- Addresses
- Orders
I want to get use 5 from the database, and their address, and orders, in one query.
Joining Users and Addresses would return all the Addresses the user has. Each Address as a row, with Users columns. But, when you add another table that can also return n results, how does the database return that?
I hope this isn't too confusing. I struggled to put it into better words.
If you make a JOIN from a table A to a table B ON A.UserID = B.UserID, and B.UserID is not unique, it returns as many rows as B dictates and fields selected from A are duplicated.
To put in a example, if you do:
SELECT a.Name, B.Adress FROM users A INNER JOIN adresses B ON A.UserID = B.UserID
And adresses contains 3 rows for ID 1 (Let's call him Max), then the output would be:
Max | 123 Fake St.
Max | 456 Real St.
Max | 789 Imaginary St.
The same would apply if you add a third table. Records from tables A and B will be duplicated for each match in table C.

Simplify table with repeated entries MYSQL

I have created a table as a union of two SELECT statements, say FRIENDS_AND_NEIGHBORS, and I want to remove the repetitions of the two, except that they do not coincide in all the fields.
Simplifying my case, I have a table called FRIENDS (that has pairs of users, and its link id) and a table for USER that includes ZIP_CODE, from which I get the NEIGHBORS section. I'm also fixing a reference user with USER_ID = #usr, and ZIP_CODE = #zip. Then I do the following.
CREATE TABLE FRIENDS_AND_NEIGHBORS
(SELECT
USER_ID AS FRND_ID, # Choose neighbors by zipcode.
ZIP_CODE AS FRND_ZIP, #
0 AS FRND_LINK # The reference for friendship comes later.
FROM USER
WHERE ZIP_CODE = #zip)
UNION
(SELECT
frd.FRIEND_ID AS FRND_ID,
usr.ZIP_CODE AS FRND_ZIP,
frd.LINK AS FRND_LINK
FROM FRIENDS frd
JOIN USER usr
ON frd.FRIEND_ID = usr.USER_ID
WHERE frd.USER_ID = #usr);
Then I may be counting some neighbor/friends twice, but they still differ in the FRND_LINK
column, as I gave it a zero because I couldn't join the two.
I want to remove the corresponding neighbor row that has 0, when it has been counted as a friend.
Thank you for your help.

MySQL Query - Loading records if the owner is a friend

I've got a system on my website which is very similar to Facebook, where you can post statuses and your people can comment on your status, like it etc. This all gets inserted in the database in the following format, with child tables of the likes and comments with foreign keys set up in case the parent status gets deleted, the likes and comments get deleted with it.
I also have a friends table which contains the user ID of the user that started the friend request, the user ID of the user that has to either accept it or deny it, and the status of the record, whether it's accepted, denied or pending.
There's also a "users" table which contains the normal malarkey, such as emails, passwords etc. All records have a unique ID however, in the column "userID".
The query I have at the moment loads all statuses regardless of whether the status owner is your friend or not. The current query looks like this (I'm working in ColdFusion so ## are the variables passed to the function)
SELECT *,
(SELECT COUNT(*) FROM status_likes WHERE likeStatusID=statusID) AS StatusLikeCount,
(SELECT COUNT(*) FROM status_comments WHERE SID=statusID) AS StatusCommentCount
FROM status, users
WHERE statusOwner=userID
AND statusType='user'
ORDER BY statusDateTime DESC
LIMIT #args.indexStart#,#args.indexEnd#;
I need this query to only load statuses if the owner of the status is your friend. I can call a query to load a users friends and append a string containing the user ID's of all the friends, such as: "652,235,485,975" etc.
I tried doing an IN in the query so there was an extra line:
AND (statusOwner=#val(args.userID)# OR statusOwner IN (#usersFriendsString#))
However this brought back duplicate results and when I tried GROUP BY on the status owner, it didn't bring back records that it should have.
Any MySQL gurus out there able to help?
You should use something like that :
SELECT
s.*,
(SELECT COUNT(*) FROM status_likes WHERE likeStatusID=s.statusID) AS StatusLikeCount,
(SELECT COUNT(*) FROM status_comments WHERE SID=s.statusID) AS StatusCommentCount
FROM Users u
JOIN Friend f ON f.friendOwner = u.id
JOIN Status s ON s.statusOwner = f.id
WHERE u.id = <...>
ORDER BY s.statusDateTime DESC
You can use WHERE clause if you can't use a JOIN instruction.
Or you can use a IN instruction populated by a SELECT that retrieve all requiered status ids.

SQL Query/Procedure with user input to view all persons meeting a criteria

I have an SQL database which I need to create a procedure or query that is linked to a web front end where the user can type in a value which will be in one of the columns of the database. The user types in the value, submits the command (just normal text entry in a textbox in the website), a query is ran in the background to view all persons who have this value in the column under their entry.
User entry to determine the outcome for a view of specific people.
SQL Side I have currently but not certain it is correct, works but not as intended!
I have a table with people in it and a model of interest value column.
Each model of interest is just a number 1-7 which relates to a product range in another table. So 1 = a Corsa, 2 = Astra, 3 = Vectra etc.
So in the persons table, they will have purely a 1 or a 2 etc. Now I need it to be linked to the model table so if it sees 1 it looks for Corsa rather than the number 1.
A user types in the frontend, select all users interested in a Corsa, it will look up the word corsa and match it to the value 1, then search for 1 in the model of interest column in the person table.
So far I have the following query. Any suggestions as I'm stumped for today. Will try again tomorrow.
SELECT TOP 100 [ld_idno]
,[ld_company]
,[ld_decisionmaker]
,[ld_decisionmaker_workphone]
,[ld_decisionmaker_mobile]
,[ld_decisionmaker_email]
,[ld_discussion_model]
FROM [FMLive204].[dbo].[tblLeads]
SELECT a.po_word
FROM dbo.tblPopulation a
INNER JOIN dbo.tblLeads b
ON ld_discussion_model = po_idno
WHERE [po_word]='Corsa'
SELECT TOP 100 Unique Records
company name
customer name
customer workphone]
customer mobile]
customer email]
[ld_discussion_model] Model of interest = 1
FROM [FMLive204].[dbo].[tblLeads]
SELECT a.po_word
FROM dbo.tblPopulation a (table a)
INNER JOIN dbo.tblLeads b (table b)
ON ld_discussion_model = po_idno (if the model of interest 1 is the same as an entry in the other table, pick the value in the next columne (po_word)
WHERE [po_word]='Corsa'
Daniel,
Below I've outlined the stored procedure which would require the userdata (e.g. Corsa entered from the website) and return all fields from tblpopulation where 'po_idno' is in the list matched against the tblLeads. Not having the tblpopulation definition I'm guessing for field name 'po_idno' is the field which has the value 1-7 in it.
Create PROCEDURE [dbo].[sp_find_person] (#UserData varchar(6))
AS
BEGIN
SELECT Top 100 * FROM [FMLive204].[dbo].tblpopulation
where po_idno in (SELECT po_idno FROM dbo.tblLeads b
JOIN dbo.tblPopulation a
ON ld_discussion_model = po_idno
WHERE [po_word]=#UserData)
Once you create the procedure you'll have to execute it which more information can be found # http://msdn.microsoft.com/en-us/library/ms189915.aspx