Linking tables in mysql - php

I need to know how to link two tables in a php/mysql set up then rank the results?
Here is my situation.
I have a stories table:
storyid
writerid
title
story
submitdate
and a votes table
voteid
userid
storyid
vote
I store a vote up as a 1 and a vote down as a -1
I am looking for a way to join these two table then rank/sort the stories by the number of votes they recieve.
I am open to any ideas about how to do so or a different possible database schema.

I prefer to keep the names of my tables singular. It's not a "Stories" table; it's a "Story" table with multiple rows.
A vote can only be attributed to a single story, so it's a one-to-many relationship between the two. I'd put the foreign key in the votes table and let it point out the story it's associated with. Change your schema if you agree: remove the voteid from the story table and make storyid in vote a foreign key to the story table.
But with that said, perhaps you can try a query like this:
select stories.storyid, sum(vote=-1) as down, sum(vote=1) as up
from stories
inner join votes on (stories.storyid = votes.storyid)
group by stories.storyid
Corrected per ypercube's comment below.

Related

PHP function to return data from database as table with table relationships

I have a requirement for a PHP function that takes table or tables and the required columns from those db tables and returns a html table containing the data. I know how to do this for one table but am struggling with how to make this more dynamic
My thinking for one table would be to have a function that takes the table name and then an array of columns and then just selects the data from the table and then loops through it constructing the data as html and then return that from the function.
As an example my database has two tables; users and orders
users
|----------------------------|
|user_id|first_name|last_name|
|-------|----------|---------|
orders
|----------------------|
|order_id|user_id|total|
|--------|-------|-----|
Now with the function discussed above it would be easy to generate a table for all the users or orders but what I would like to do is have a function where I could dynamically join tables and for example list all users and the number of orders they've made or list all orders from user x. I know that this would be possible with many different functions but I'm really interested in developing a way of doing this dynamically and basically building all the relationships somehow in the program and then be able to call one function and request columns x,y and z
My thinking so far would be (again for this example) somehow define that number of orders for user i = count(order_id) where user_id = i
Hope this makes sense and thank you in advance
The INFORMATION_SCHEMA.KEY_COLUMN_USAGE table can be used to find all foreign key relationships from a particular table to other tables, e.g:
SELECT `TABLE_NAME`,
`COLUMN_NAME`,
`REFERENCED_TABLE_NAME`,
`REFERENCED_COLUMN_NAME`
FROM `INFORMATION_SCHEMA`.`KEY_COLUMN_USAGE`
WHERE `TABLE_SCHEMA` = SCHEMA() -- current schema
AND `REFERENCED_TABLE_NAME` IS NOT NULL
AND `TABLE_NAME` = 'orders'; -- name of table to get relationships to other tables
This should return something like the following:
+--------------+-------------+-----------------------+------------------------+
| TABLE_NAME | COLUMN_NAME | REFERENCED_TABLE_NAME | REFERENCED_COLUMN_NAME |
+--------------+-------------+-----------------------+------------------------+
| orders | user_id | users | user_id |
+--------------+-------------+-----------------------+------------------------+
The above can be done in PHP and the results can then be iterated over to dyamically construct a query that selects from those tables, joining on the listed columns. Will leave that part as an exercise ;-)
You wouldn't need to make a function to grab data from first table then loop around them and get data from the second table.
SQL can do this for you with 1 hit on the database.
All what you need to do is join the two tables, and grab the data you want..
If I understood what you need right, you want to grab all users id from the first table, and get their order count from the second table.
A simple join or selecting from both table could do that, and I suggest something like:
Select a.user_id, b.count(order_id)
FROM table1 as a, table2 as b
WHERE a.user_id = b.user_id
Group By a.user_id
Or you could join the tables and do a similar task.
I am assuming you're gonna access database from PHP code, so try that, and give me back your feedback.
This is easy to implement but we have to fix few things.
Our requirement:
1. Identify Tables according to column name.
2. How we can Join those tables.
3. How to resolve ambiguity of columns.
Solution:
Unique column name for each field or no table has duplicate column name.
To achieve it we should have fix table prefix for each table.
for example:
your column name could be odr_orderid and usr_orderid.
Now by identifying unique prefixes, we can identify tables.
Now issue arises how to join these tables
To resolve it:
Create an another table strong JOIN keys and JOin type Left, right,inner or full.
Thats all Now you can make the query as you want.

Double query with WHERE IN, or join

We have two major mysql (innodb) tabels. Both containing millions of records.
Here is a example of our structure
-- table 1 --
primary_id
child_id
-
-- table 2 --
id
structure
contents
It's not like this, but for the question it's the same.
We need to fetch about 50.000 records from table 2, that are linked to primary id 2022.
What is the most quickly way to do this.
This is what we came up with:
1)
Do a select with a join on the two tables.
2)
Do a select of the ids in table 1 getting 200.000 records and then a select WHERE IN (all id's) and a filter on the structure there.
Any ideas?
i would go with a join. Select records from first table with the primary_id you need and join the second table on the ids

How to create relationship between tables?

I have one table for posting new articles and the content of the table is printed using a while loop.
Now I want the viewers to be able to comment on the article so I created another table for comments and a form under article in the while loop, but whenever anybody comments on the article the comment is showed with all the articles.
Because article and comments are in one while loop and there is no relationship between the tables.
tables are as follows:
content_posts(
id int primary auto,
subject varchar,
postby varchar,
date date,
content varchar
)
comments(
id int primary auto,
name varchar,
email varchar,
body varchar
)
If you want to set up a relationship you have to determine the sense of your relationship.
One to One
Each side of the relationship is related to one and only entity. For example, nowaday, you split up the users definition in two parts :
the connection handler (password, last login date, activation)
the profile info (username, email, favourite movie...)
One profile has only one handler and one handler has only one profile.
In that case each table has to be added with a foreign key that takes the identifier of each entity.
One to Many
The case that you have with your blog. One article has many comments, one comments has one and only one article.
So, in your comment table, you have to add your foreign key that is a link to your article.id.
Then to select the comment that are in one article, you have to make a WHERE :
SELECT * FROM comment_table WHERE id_article = 1 -- for your first article,
If you want to load info from your article table and your comment table, you have to use the JOIN command :
SELECT comment_table.*, article_table.* FROM article_table
JOIN comment_table ON article_table.id = comment_table.id_article
many to many
each entity can be associated to many of the other. For example, il you provide tags to your articles : each tag cas be assigned to many articles, each article can have many tags.
In this case, you have to create a new table which only have tag_id and article_id.
To select one article with his tags, you have to make a double join :
SELECT article.*, tags.* FROM article_table article
JOIN tags_in_article tia ON tia.id_article = article.id
JOIN tag_table tags ON tia.id_tag = tag.id
WHERE article.id = 1
You can try linking the tabels by the aticle id column: for example: ARTICLES with the column id and COMMENTS with a field named article_id which will contain the id of the corresponding article.
Then you can use an INNER JOIN like this
SELECT * FROM ARTICLES as t1 INNER JOIN COMMENTS as t2 ON t1.id = t2.article_id
Hope it helps!
You need to define primary key in your article table, normally called id, and a foreign key in your comments table. This key relationship, in this case a one to many, is then used to ensure only comments related to a specific article are displayed. Using the id you would loop through the foreign keys finding the matches.

MySQL - Database design - separate tables for users and profile

From what I've been reading online, I understood that it's better to split the data into more tables, if possible because of the access times.
Right now I have a table in which I am storing usernames, passwords and join date
This is how my table looks:
'user'
'user_id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
user_username VARCHAR(80) NOT NULL,
user_password VARCHAR(255) NOT NULL,
user_join_date INTEGER UNSIGNED NOT NULL,
PRIMARY KEY (user_id) ');
I am trying to create a new table called profiles in which I want to store first name, last name, email, age and gender. What I think is that I need a one-to-one relationship, so I should be using the user_id but I'm not really sure how to implement it.
Should I create another table called profiles with
profiles
profiles_id
first_name
last_name
email
age
gender
and another one which should be the relationship ? e.g.
user_profiles
----------
user_id
profiles_id
Is this right? How would the SQL look for the user_profiles?
Thanks
Don't split the tables. Just add the new columns to your existing user table. You might find later on that splitting tables is a good idea based on actual queries and usage patterns but until you have that kind of data, keep things simple.
If you must create a profile table, don't create a user_profiles table. That would allow an m-to-n relationship which is probably not what you want. A simple user_id column in profiles is better. In fact, it could be both a foreign key and the primary key to make sure that each user row only have one and only one profile row (although by splitting the tables you might still have a user with no profile).
Usually, you create an association table, like user_profiles you have described when one user could have more than one profile, and/or one profile could belong to one or more user.
As you have said, here you have a one-to-one relationship between user and profile. So, you can simply add a user_id column to your profile table, and define it as a foreign key to user table.
Then, a simple JOIN will allow you to query both tables at the same time:
SELECT u.*, p.*
FROM user u
JOIN profile p ON u.user_id = p.user_id
Add a new field in the User table, ProfileId, and set it as Foreign Key (FK). Each time you create a User, you have to assign to it a profile (which will be the ProfileId PK from profile table).
If you want to see also the profile information of a user, you have to do a join
Select username, first_name,second_name
From user u, profile p
Where u.profileId = p.profileId
this
user_profiles
----------
user_id
profiles_id
is used in a many-to-many relationship. By example, you want to assign to an admin some privileges, but those privileges can be also assigned to more admins. Then, you have to create a 3rd table to solve this problem. Here is an example, but you don't need to do this.
You could add a user_id field to your profiles table and JOIN the tables on user_id.
SELECT user.user_username, ..., profiles.first_name, ...
FROM user
INNER JOIN profiles
ON user.user_id = profiles.user_id
This should fetch data combining information from those rows where the JOIN condition is met (i.e. user.user_id = profiles.user_id).
It is true that having more than one tables is a good idea. I am not sure what you mean about access time, but there are other advantages.
- Your users database containing passwords etc is "sacred", you never change its structure and you limit the rights to it (read, write) to the strict minimum.
- You can then have several "satelites" tables such as profiles, private messages, etc which are more flexible, less sensitive and which you can change all the time.
About your question per se, there is no need for a separate table with the relationships. In fact is a very bad idea which will complicate your queries and doesn't have any advantage. Instead, in your profiles database you will have one column that refers back to the user id.
users
--------
id
user_name
email
password
users_profiles
---------
id
user_id
favourite_animal
Table user
user_id |user_username |user_password |user_join_date |profile_id
Table profile
profile_id |first name |last name |email |age |gender
When selecting a user by user id:
SELECT u.*, p.* FROM user AS u INNER JOIN `profile` AS p ON u.profile_id = p.profile_id WHERE u.user_id = 1
But a user should only one gender, one age, one name and surname. Maybe e-mail adresses might be many. I suggest you there is no need to join tables which have a 1-to-1 relation. Instead merge those tables.

Delete Entrys in different Tables MysQL Query

I'm trying to figure out, how to delete some entries in the database with INNER JOIN.
I have 2 different Tables, USER and BLOGS
I'm trying to delete all entries in BLOGS, when the entry belongs to a user, which does not exist. So in USER table there are all users listed with a unique ID. This same ID also is in table BLOGS.
A Query like this would work, but I guess this is not even a correct mysql query:
delete from BLOGS where `id` does not exist in USER;
I know, the command "does not exist" doesn't really work.
Any Idea? Thanks in advance.
try this
DELETE FROM BLOGS WHERE `id` NOT IN
(SELECT id FROM `USER`);
The fastest way is to do a left join and see which entry has no corresponding row in the other table.
DELETE FROM
blogs
LEFT JOIN users ON blogs.id = users.id
WHERE users.id IS NULL;
Another syntax close to yours is possible, but it's not performant, since for every row in blogs table, the whole users table is read (assuming there's no index).

Categories