We changed database schema and moved a relationship between users/accounts from a 1-1 to a many to many using a join table accounts_users.
So we have
accounts,
users,
accounts_users (user_id and account_id)
Our data is still 1-1, and we have decided to move back. So I need sql to move back:
To Migrate I used:
INSERT INTO accounts_users (account_id,user_id) SELECT id AS account_id, user_id AS user_id FROM accounts
To move back I have tried:
UPDATE
accounts
SET
user_id = ru.user_id
FROM
accounts r, accounts_users ru
ON
r.id = ru.account_id
Update accounts
Set r.user_id = ru.user_id
FROM accounts r, accounts_users ru
WHERE r.id = ru.account_id
SELECT accounts_users.user_id
INTO accounts
FROM accounts_users
INNER JOIN accounts
ON accounts.id = accounts_users.account_id
All of these give a sql error of some sort. Im guessing its because my sql is ambiguous, and I need some sort of select first or min or something like that.
** To be clear, Im sure still have the 1-1 relationship in the data, but I cant figure out the sql to bring the data from the existing tables back into the original tables. What im looking for is some working sql that will take the data from accounts_users and put the user_id into the account table. Thanks, Joel
You could try...
UPDATE accounts
SET user_id = (SELECT user_id
FROM accounts_users
WHERE accounts_users.accounts_id = accounts.accounts_id);
That'll get pretty tedious if you have a lot of columns in accounts_users that have to go back in accounts, though, and won't work if there is any problems with the ids (hence my previous answer). How many columns are there?
If your mapping is 1-1 then just select the first result (you know there is only one)
Related
I've tried searching an answer for this and I can't realy find the one that fits what I'm looking for.
I'm making a small web application that allows an admin to create course material and a test, that a user will be assigned.
What I am trying to figure out, is how a user, who has been assigned a course, can access that course by clicking a button.
I have created one table which stores the user information, with a user ID being a primary key. I have a course table, which stores all materials and the course's test, with a course id being that table's primary key.
I made a third table which is an assigned_courses table, it contains two foreign keys. One referencing the user id from the user table, and one referencing the course id on the course table.
I've inserted a few images to show what you mean.
I can't quite figure out the Sql syntax to pull course materials and test based on the assigned_course table.
All feedback appreciated. This is the two foreign keys that reference the user id (id) and the course id(u_id)
Not sure what column names you have so I used * instead. You can use JOIN (AKA INNER JOIN) to link the tables together. You join on the primary keys of the 2 tables.
I have created one table which stores the user information, with a
user ID being a primary key. I have a course table, which stores all
materials and the course's test, with a course id being that table's
primary key.
I used id for your user table and course_id for the course table. Change as needed.
Find all courses for a given user.
SELECT a.*
FROM course a
JOIN assigned_course b ON a.course_id = b.id
WHERE b.u_id = :userId
;
Find all users for a given course.
SELECT a.*
FROM user a
JOIN assigned_course b ON a.id = b.u_id
WHERE b.id = :courseId
;
EDIT #1 - Subquery without JOIN
Thanks for your feedback, as I stated above, I was hoping to avoid a
join.
I highly recommend you learn joins. They are essential when you need to query more than 1 table. In this case, you can use a sub-query to find matching courses for a user but you won't be able to access that user data at the same time; that is the power of a join. I'll include a final example underneath showing how to get courses and user data at the same time.
Find all courses for a given user (using sub-query)
SELECT a.*
FROM course a
WHERE course_id IN (
SELECT id
FROM assigned_course b
WHERE u_id = :userId)
;
Final example showing courses related to users (many-to-many)
SELECT * -- You now have access to a, b, and c data
FROM course a
JOIN assigned_course b ON a.course_id = b.id -- joined by PKs
JOIN user c ON c.id = b.u_id -- joined by PKs
WHERE c.id = :userId
;
It sounds to me like you want to use SQL Join syntax which goes as follows:
select column1, column2, column3 etc...
from table1
join course on table1.id = course.id
join assigned_course on table1.id = assigned_course.id
replace the column1,2,3 etc with the actual column names, and replace the foreign_key_name with the actual name of the foreign key in the sub-table and the same for the user_primary_key
you can find some other examples of mysql joins here
as far as how to implement them into your html or php file, that is a very different question and would require knowing alot more about how your code is setup in the form
a place that is pretty user friendly is that might help with pulling the data is here just make sure you are aware of using prepared statements for your code
I'm currently having a problem with a legacy app I just inherited on my new job. I have a SQL query that's way too long to respond and I need to find a way to fasten it.
This query acts on 3 tables:
SESSION contains all users visits
CONTACT contains all the messages people have been sending through a form and contains a "session_id" field that links back to the SESSION id field
ACCOUNT contains users accounts (people who registered on the website) and whose "id" field is linked back in SESSION (through a "SESSION.account_id" field). ACCOUNT and CONTACT are no linked in any way, besides the SESSION table (legacy app...).
I can't change this structure unfortunately.
My query tries to recover ALL the interesting sessions to serve to the administrator. I need to find all sessions that links back to an account OR a contact form.
Currently, the query is structured like that :
SELECT s.id
/* a few fields from ACCOUNT and CONTACT tables */
FROM session s
LEFT JOIN account act ON act.id = s.account_id
LEFT JOIN contact c on c.session_id = s.id
WHERE s.programme_id = :program_id
AND (
c.id IS NOT NULL
OR
act.id IS NOT NULL
)
Problem is, the SESSION table is growing pretty fast (as you can expect) and with 400k records it slows things down for some programs ( :programme_id in the query).
I tried to use an UNION query with two INNER JOIN query, one between SESSION and ACCOUNT and the other one between SESSION and CONTACT, but it doesn't give me the same number of records and I don't really understand why.
Can somebody help me to find a better way to make this query ?
Thanks a lot in advance.
I think you just need indexes. For this query:
SELECT s.id
/* a few fields from ACCOUNT and CONTACT tables */
FROM session s LEFT JOIN
account act
ON act.id = s.account_id LEFT JOIN
contact c
ON c.session_id = s.id
WHERE s.programme_id = :program_id AND
(c.id IS NOT NULL OR act.id IS NOT NULL);
You want indexes on session(programme_id, account_id, id), account(id) and contact(session_id).
It is important that programme_id be the first column in the index on session.
#Gordon already suggested you add an index, which is generally the easy and effective solution, so I'm going to answer a different part of your question.
I tried to use an UNION query with two INNER JOIN query, one between
SESSION and ACCOUNT and the other one between SESSION and CONTACT, but
it doesn't give me the same number of records and I don't really
understand why.
That part is rather simple: the JOIN returns a result set that contains the rows of both tables joined together. So in the first case you would end up with a result that looks like
session.id, session.column2, session.column3, ..., account.id, account.column2, account.column3, ....
and a second where
session.id, session.column2, session.column3, ..., contact.id, contact.column2, contact.column3, ....
Then an UNION will faill unless the contact and account tables have the same number of columns with correspoding types, which is unlikely. Otherwise, the database will be unable to perform a UNION. From the docs (emphasis mine):
The column names from the first SELECT statement are used as the column names for the results returned. Selected columns listed in corresponding positions of each SELECT statement should have the same data type. (For example, the first column selected by the first statement should have the same type as the first column selected by the other statements.)
Just perform both INNER JOINs seperately and compare the results if you're unsure.
If you want to stick to an UNION solution, make sure to perform a SELECT only on corresponding columns : doing SELECT s.id would be trivial but it should work, for instance.
I have a USERS table and a LOGS table. The LOGS table was normalized, storing only a user_id until recently, when I decided to denormalized it for performance reasons. After this change, I have username and user_role columns as part of LOGS table as well.
Now I need to update existing records of the LOGS table to fill out username and user_role columns, based on the value of user_id column, so that data becomes consistent. How can go about achieving this? I'm looking for possibly an SQL script that I can run on the database server.
Asim
Use something like this. You can just join the users table
UPDATE LOGS l
INNER JOIN users u ON u.id=l.user_id
SET l.username=u.name,
l.user_role=u.role
WHERE ... if necessary
UPDATE:
UPDATE LOGS l
INNER JOIN (select l.id as log_id, u.*
from logs l join users u ON u.id=l.user_id
order by l.id
limit 10) sub ON sub.id=l.id
SET l.username=sub.name,
l.user_role=sub.role
I'm writing what is a pretty simple 2-step SQL Query.
I have one table called Users and another called ProfileCharacteristics.
**Users Table:**
UserId [PK]
UserName
**ProfileCharacteristics Table:**
UserId [FK]
.....(other data)
I'm trying to get access to (other data), but I only have the UserName available. So what I'm presently doing is running one SQL Query that matches the UserName to the UserId and stores the UserId value.
Then, I'm pulling all values that match to UserId in ProfileCharacteristics in a separate query. I have a gut feeling that I could combine these two queries into one, but I'm not sure how.
Any pointers?
EDIT: The start of a JOIN?
SELECT * FROM ProfileCharacteristics
INNER JOIN Users
ON ....
What you're looking for is an INNER JOIN:
SELECT pc.*
FROM ProfileCharacteristics pc
JOIN Users u ON pc.UserId = u.UserId
WHERE U.UserName = 'someuser'
A Visual Explanation of SQL Joins
I have 3 tables called
_partnership,
_partners,
_partnership_arm._partners = stores basic partner information
_partnership_arm = stores partnership arm details
_partnership = stores partners partnership records which includes the partner_id
arm_id which reference _partners.partner_id and _partnership_arm.arm_id.
So as an admin i want to select all details from the _partnership table which join other table reference without a where clause, but am having issue doing it.
here is my code
SELECT
_partnership.*,
_partners.names,
_partnership_arm.arm_name
FROM
`_partnership`
JOIN
`_partners`,`_partnership_arm` ON
_partnership.partner_id = _partners.partner_id
AND
_partnership.arm_id = _partnership_arm.arm_id
I also want a user to be able to select using a where clause
Please how can i achieve this?
Thank you.
SELECT
_partnership.*,
_partners.names,
_partnership_arm.arm_name
FROM
`_partnership`
JOIN
`_partners` ON _partnership.partner_id = _partners.partner_id
JOIN
`_partnership_arm` ON _partnership.arm_id = _partnership_arm.arm_id