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;
Related
I have a query i have been working on trying to get a specific set of data, join the comments in duplicate phone numbers of said data, then join separate tables based on a common field "entry_id" which also happens to be the number on the end of the word custom_ to pull up that table.
table named list and tables containing the values i want to join is custom_entry_id (with entry_id being a field in list in which i need the values of each record to replace the words in order to pull up that specific table) i need entry_id from the beginning part of my query to stick onto the end of the word custom for every value my search returns to get the fields from that custom table designated for that record. so it will have to do some sort of loop i guess? sorry like i said I am at a loss at this point
this is where i am so far:
SELECT * ,
group_concat(comments SEPARATOR '\r\n\r\n') AS comments_combined
FROM list WHERE `status` IN ("SALEA","SALE")
GROUP BY phone_number
//entry_id is included in the * as well as status
// group concat combines the comments if numbers are same
i have also experimented on test data with doing a full outer join which doesnt really exist. i feel if you can solve the other part for me i can do the joining of the data with a query similar to this.
SELECT * FROM test
LEFT JOIN custom_sally ON test.num = custom_sally.num
UNION
SELECT * FROM test
RIGHT JOIN custom_sally ON test.num = custom_sally.num
i would like all of this to appear with every field from my list table in addition to all the fields in the custom_'entry_id' tables for each specific record. I am ok with values being null for records that have different custom fields. so if record 1 has custom fields after the join of hats and trousers and record 2 has socks and shoes i realize that socks and shoes for record 1 will be null and hats and trousers for record 2 will be null.
i am doing all this in phpmyadmin under the SQL tab.
if that is a mistake please advise as well. i am using it because ive only been working with SQl for a few months. from what i read its the rookie tool.
i might be going about this all wrong if so please advise
an example
i query list with my query i get 20,000 rows with columns like status, phone_number, comments, entry_id, name, address, so on.
now i want to join this query with custom fields in another table.
the problem is the custom tables' names are all linked to the entry_id.
so if entry_id is 777 then the custom table fields are custom_777
my database has over 100 custom tables with specials fields for each record depending on its entry_id.
when i query the records I don't know how to join the custom fields that are entry_id specific to the rest of my data.i will pull up some tables and data for a better example
this is the list table:
this is the custom_"entry_id"
Full Outer Join in MySQL
for info on full outer joins.
Here is my Database structure (basic relations):
I'm attempting to formulate a one-line query that will populate the clients_ID, Job_id, tech_id, & Part_id and return back all the work orders present. Nothing more nothing less.
Thus far I've struggled to generate this Query:
SELECT cli.client_name, tech.tech_name, job.Job_Name, w.wo_id, w.time_started, w.part_id, w.job_id, w.tech_id, w.clients_id, part.Part_name
FROM work_orders as w, technicians as tech, clients as cli, job_types as job, parts_list as part
LEFT JOIN technicians as techy ON tech_id = techy.tech_name
LEFT JOIN parts_list party ON part.part_id = party.Part_Name
LEFT JOIN job_types joby ON job_id = joby.Job_Name
LEFT JOIN clients cliy ON clients_id = cliy.client_name
Apparently, once all the joining happens it does not even populate the correct foreign key values according to their reference.
[some values came out as the actual foreign key id, not even
corresponding value.]
It just goes on about 20-30 times depending on largest row of a table that I have (one of the above).
I only have two work orders created, So ideally it should return just TWO Records, and columns, and fields with correct information. What could I be doing wrong? Haven't been with MySQL too long but am learning as much as I can.
Your join conditions are wrong. Join on tech_id = tech_id, not tech_id = tech_name. Looks like you do this for all your joins, so they all need to be fixed.
I really don't follow the text of your question, so I am basing my answer solely on your query.
Edit
Replying to your comment here. You said you want to "load up" the tech name column. I assume you mean you want tech name to be part of your result set.
The SELECT part of the query is what determines the columns that are in the result set. As long as the table where the column lives is referenced in the FROM/JOIN clauses, you can SELECT any column from that table.
Think of a JOIN statement as a way to "look up" a value in one table based on a value in another table. This is a very simplified definition, but it's a good way to start thinking about it. You want tech name in your result set, so you look it up in the Technicians table, which is where it lives. However, you want to look it up by a value that you have in the Work Orders table. The key (which is actually called a foreign key) that you have in the Work Orders table that relates it to the Technicians table is the tech_id. You use the tech_id to look up the related row in the Technicians table, and by doing so can include any column in that table in your result set.
some help here please with (advanced) mysql. Example illustrates the issue much better. So..
I have a predefined value pair table PARTNERS with partner1 and partner2 columns. And then there is another table PROJECTS which has partner1 and partner2 columns.
So, I want to select all PROJECTS where columns partner1 and partner2 are within the actual partners table described above.
Obviously, I cannot simply indicate "where partner1=... and/or partner2=..." because there would be no check of whether those two are partners (as defined in the PARTNERS table). (Just in case: there are projects with partner1 and partner2 not in the partner relationships.)
I don't think that kind of query is possible at all since it has the condition stored in the result. But would be happy if one can prove otherwise.
Thanks
It sounds like you need a query that will give you rows from PROJECTS where partner 1 and partner 2 are both the same as they are in any row in PARTNERS. So do an inner join:
SELECT * FROM projects
INNER JOIN partners
ON projects.partner1 = partners.partner1
AND projects.partner2 = partners.partner2
If you're up for restructuring your tables, it might make more sense to assign a unique ID to every row in PARTNERS, and use that ID in the PROJECTS table. That way instead of storing two columns of redundant data, you just have one column indicating which pair of students is on the project.
I have three tables: students, interests, and interest_lookup.
Students has the cols student_id and name.
Interests has the cols interest_id and interest_name.
Interest_lookup has the cols student_id and interest_id.
To find out what interests a student has I do
select interests.interest_name from `students`
inner join `interest_lookup`
on interest_lookup.student_id = students.student_id
inner join `interests`
on interests.interest_id = interest_lookup.interest_id
What I want to do is get a result set like
student_id | students.name | interest_a | interest_b | ...
where the column name 'interest_a' is a value in interests.name and
the interest_ columns are 0 or 1 such that the value is 1 when
there is a record in interest_lookup for the given
student_id and interest_id and 0 when there is not.
Each entry in the interests table must appear as a column name.
I can do this with subselects (which is super slow) or by making a bunch of joins, but both of these really require that I first select all the records from interests and write out a dynamic query.
You're doing an operation called a pivot. #Slider345 linked to (prior to editing his answer) another SO post about doing it in Microsoft SQL Server. Microsoft has its own special syntax to do this, but MySQL does not.
You can do something like this:
SELECT s.student_id, s.name,
SUM(i.name = 'a') AS interest_a,
SUM(i.name = 'b') AS interest_b,
SUM(i.name = 'c') AS interest_c
FROM students s
INNER JOIN interest_lookup l USING (student_id)
INNER JOIN interests i USING (interest_id)
GROUP BY s.student_id;
What you cannot do, in MySQL or Microsoft or anything else, is automatically populate columns so that the presence of data expands the number of columns.
Columns of an SQL query must be fixed and hard-coded at the time you prepare the query.
If you don't know the list of interests at the time you code the query, or you need it to adapt to changing lists of interest, you'll have to fetch the interests as rows and post-process these rows in your application.
What your trying to do sounds like a pivot.
Most solutions seem to revolve around one of the following approaches:
Creating a dynamic query, as in Is there a way to pivot rows to columns in MySQL without using CASE?
Selecting all the attribute columns, as in How to pivot a MySQL entity-attribute-value schema
Or, identifying the columns and using either a CASE statement or a user defined function as in pivot in mysql queries
I don't think this is possible. Actually I think this is just a matter of data representatioin. I would try to use a component to display the data that would allow me to pivot the data (for instance, the same way you do on excel, open office's calc, etc).
To take it one step further, you should think again why you need this and probably try to solve it in the application not in the database.
I know this doesn't help much but it's the best I can think of :(
I've got 3 tables that are something like this (simplified here ofc):
users
user_id
user_name
info
info_id
user_id
rate
contacts
contact_id
user_id
contact_data
users has a one-to-one relationship with info, although info doesn't always have a related entry.
users has a one-to-many relationship with contacts, although contacts doesn't always have related entries.
I know I can grab the proper 'users' + 'info' with a left join, is there a way to get all the data I want at once?
For example, one returned record might be:
user_id: 5
user_name: tom
info_id: 1
rate: 25.00
contact_id: 7
contact_data: 555-1212
contact_id: 8
contact_data: 555-1315
contact_id: 9
contact_data: 555-5511
Is this possible with a single query? Or must I use multiple?
It is possible to do what you're asking in one query, but you'd either need a variable number of columns which is evil because SQL isn't designed for that, or you'd have to have a fixed number of columns, which is even more evil because there is no sensible fixed number of columns you could choose.
I'd suggest using one of two alternatives:
1. Return one row for each contact data, repeating the data in other columns:
5 tom 1 25.00 7 555-1212
5 tom 1 25.00 8 555-1315
5 tom 1 25.00 9 555-5511
The problem with this of course is that redundant data is normally a bad idea, but if you don't have too much redundant data it will be OK. Use your judgement here.
2. Use two queries. This means a slightly longer turnaround time, but less data to transfer.
In most cases I'd prefer the second solution.
You should try to avoid making a large number of queries inside a loop. This can almost always be rewritten to a single query. But if using two queries is the most natural way to solve your problem, just use two queries. Don't try to cram all the data you need into a single query just for the sake of reducing the number of queries.
Each row of result must have the same columns, so you can't aggregate multiple rows of contact not having the other columns as well.
Hopefully, this query would achieve what you need:
SELECT
u.user_id as user_id,
u.user_name as user_name,
i.info_id as info_id,
i.rate as rate,
c.contact_id as contact_id,
c.contact_data as contact_data
FROM users as u
LEFT JOIN info as i ON i.user_id = u.user_id
LEFT JOIN contacts as c ON c.user_id = u.user_id