At the moment I have three tables that I am trying to connect and figure out what queries will get the results I need and also follow best practices. MySQL is still pretty new to me, and this is my first stumbling block that I can't figure out.
I am trying to build a simple URL shortener that can "link" multiple long URLs to one short URL. I basically want to have a link www.example.com/google then have google.com, google.co.uk, google.it, etc... and GEO target when the user accesses the link.
My three tables are set up as:
short_id | user_id | short_url //Short URL Table
long_id | user_id | long_url | country_code //Long URL table
user_id | name | password | email | created //User table
I am not sure if foreign keys are the best route. Also, I understand how to add a user, but what queries would I have to run to have a user add a short/long url and have the user_id field in "user" table match the user_id fields in the other tables.
Thanks for the help.
select * from short_url_table
left join long_url_table
using (user_id)
left join user_table
using (user_id) ;
Related
I recently cleaned up my web app's code. My web app is a simple social network with Add,Remove,etc procedures. I have a php file which I call when a user want to remove a contact from his friend list.
I came up with a strange bug in my application that I haven't estimate the time I wrote it.
The Bug
Let's say we have two friend emails in our list.
georgeMARK#email.com
MARK#email.com
The contact emails are stored in a MYSQL DB column with name Contacts and every email is separated by a semicolon (;) symbol. So our example's column will look like this (depend on which user has added lastly it can be vice versa):
georgeMARK#email.com;MARK#email.com;
So assume that our user wants to remove MARK from his contacts. He presses the button and ... both email's have gone.!
Have a look in my PHPMyAdmin Panel I found that what has left from the column is this:
george
The problem is in my PDO SQL statement that I use to remove accounts from my column.
$STH = $DHB->prepare("UPDATE `Users` SET `Contacts` = REPLACE(`Contacts`, :email, '') WHERE `UserEmail` = :my_email");
The REPLACE function just replaces all the instances of the :email and thats awful. I use the same approach many times in my application and I understand that this will cause my the same bug to appear elsewhere too.
My question is how can I delete a user's email without affecting the others 'instances'? Do I have to change my point of view and how what do I need to do?
The fast dirty way is to prepend a semicolon to all Contacts field, so that entries as like this:
;georgeMARK#email.com;MARK#email.com;
then you can replace it in this way:
$emailToDelete = ";$emailToDelete;"
... REPLACE(`Contacts`, :email, ';') ...
A better approach can be to store contacts data in a more suitable format (like JSON).
The best solution is to create a relationships table and delete all the entries relative to contact to delete.
Structure
Maybe create a structure like this:
Table Users
id | Name | Email
-----------------
1 | John | john#example.com
2 | Jane | jane#example2.com
Table Friendships
User1_id | User2_id
-------------------
1 | 2
Select users
SELECT * FROM Users WHERE name=:name
Select friends
SELECT
*
FROM
Friendships
LEFT JOIN
Users
ON
Friendships.User1_id = Users.id
WHERE
User1_id=:user_id
Delete friendship
DELETE FROM Friendships WHERE User1_id=:current_user_id AND User2_id=:friend_to_remove_id
I know it makes little sense... and i'm new to using MySQL...
What i'm trying to do here is, link one tables row to another tables row...
for an example there are two tables..
one table is for user registration and same table is used for login as well...
and the next table is for user posts.. like status updates and all...
here is how i want it...
user_log_info:-
id ( primary )
firstname
lastname
username
email
password
posts:-
id ( primary )
userposts
posted_by
date_post
so as you can see, i want the user_log_info tables username to be automatically copied to posts posted_by row... And i have no idea how i can archive this...
You haven't given nearly enough information to give a full answer, but I'll do my best with what you've given.
Tables
+-----------------+ +-----------------+
| users_log_info | | posts |
+-----------------+ +-----------------+
| int ID (primary)| | int ID (primary)|
+-----------------+ | int posted_by |
+-----------------+
(I left off fields that are irrelevant to what you seem to want to do, I'm just simplifying it)
posted_by is an unofficial foreign key, or referencing the primary key of another table.
To insert, what you can do is along the lines of this:
INSERT INTO posts(...., posted_by) VALUES (...., user.ID)
Where .... is referencing all of your other information to insert
Then, to find information on someone who posted something:
SELECT * FROM users_log_info WHERE ID = Post.posted_by
Or if you want to find all posts by a user:
SELECT * FROM posts WHERE posted_by = user.ID
So, if Bob, who is User ID 3 wants to post "Hi", you might be able to do:
INSERT INTO posts(content, posted_by) VALUES('Hi', bob.ID)
And then when you are outputting the post you might do this:
post = (however you choose the post to put on the page)
userPosted = SELECT * FROM users_log_info WHERE ID = post.posted_by
print post.content + " posted by: " userPosted.Name
Essentially, the field "posted_by" is, to "posts" an arbitrary number, but you know that it links to, or references, a user. It does that by referencing "ID", which is the primary key of users_log_info, so that when you want to get information from users_log_info, is all you need to do is select the entry which has the ID that corresponds to "posted_by". I do recommend naming it something like posterID, however, for easier identification.
The question is not new in any way but it has a small twist to it.
My webpage is a membership page where users places bets. My idea is to create a new table for the users(with a naming convention like TABLE userBet+$userid) bets. User login information is already handled, my goal is now to save the bets of the user to a new table. A table which is created when users register. This will hopefully make score counting easier. Am I right or wrong? Could this be done in a better way? (Everything is done in PHP MySQL)
User registers -> Table for bets get created
"CREATE Table $userID ,id_bet, games, result, points"
And then matching this table against the correct result?
So again my questions: Is this a good way to do it? Is creating a table with the userID a smart thing to do?
EDIT
The bets is always 40 matches, which makes the tables Huge with columns and rows.
Should I make 40 Tables, one for each games instead? and put all users in there?
Am I right or wrong?
You are wrong. Dynamically altering your database schema will only make it harder to work with. There's no advantage you gain from doing so. You can do the same things by storing all bets within the same table, adding a column userid.
Posting as an answer due to author's request : )
Suggested database schema:
table matches:
id | name |
---------------
1 | A vs B |
table user_bets
id | user_id | match_id | points | result |
-------------------------------------------
1 | X | 1 | Y | Z |
Where match_id is related on matches.id
user_id = user.id
user_bets is only one table, containing all the info. No need of separate tables, as it was clear from the comments it's considered bad practice to alter the db schema via user input.
(Using PHP + mySQL)
I'm hoping someone can give me an idea as to the best way to handle this situation.
I have two tables, users and forms. The users table holds username, password, name, etc. and then the forms table holds various different html forms.
I want to specify which forms a user has access to, on a per user basis. I was thinking about creating a new field in the users table which would be 'forms_allowed' and then storing the form_id of each form the user is allowed to access, separated by commas. Something like 3,6,8,15
Then when I want to check what forms the user is allowed to access and whether they can access the form requested (etc.) i'd grab that field, explode it and check for the form_id.
This seems like a hassle and ineffective way of doing it. Does anyone have a better idea?
Thanks!
Create another table that will hold user_id and form_id pair. This is many-many relationship.
tblUsers:
user_id | name |...
tblForms
form_id | content | ...
tblRelation:
user_id | form_id
So you can simply get info with single query:
SELECT * FROM `tblUsers` AS `t`
JOIN `tblRelation` as `r` ON (t.user_id = r.user_id)
JOIN `tblForms` as `f` ON (f.form_id = r.form_id)
The following is a part of a bigger PHP script which adds or disables users from a MySQL database using a CSV file and a client id field as input.
There are two tables involved, users and users_clients. The later keeps the relationship between users and clients as an user can belong to multiple clients.
This is the structure of the tables
users structure (it has more fields)
id | int(11) (primary key)
user | varchar(100)
pass | varchar(100)
category | int(11)
date | timestamp
name | varchar(100)
email | varchar(255)
users indexes
SEARCH | user | FULLTEXT
SEARCH | name | FULLTEXT
SEARCH | email | FULLTEXT
users_clients structure
id_user | int(11)
id_client | int(11)
status | enum('active','inactive')
This is the basic flow of the script for adding each user from the CSV file:
Check if the user exists for that client.
SELECT
LOWER(user)
FROM
users u
INNER JOIN users_clients uc ON u.id = uc.id_user
WHERE
u.user = '$user'
and uc.id_client = $id_client
If it doesn't exist, add it to the database.
INSERT INTO
users ($fields,id_client)
VALUES
($values,'$id_operation')
Get the id of the inserted user.
I know I could use something like mysql_insert_id here, but what about the race conditions?.
SELECT
u.id as id
FROM
users u
WHERE
u.user = '$user'
and u.id_client = '$id_operation'
Associate the user with the corresponding client.
INSERT INTO
users_clients (id_user, id_client)
VALUES
('$id_user','$id_client')
There are currently 400.000 users in the table. The script takes 10+ minutes to process a CVS with 500 users.
How would you improve this so that it is faster?
Thanks in advance.
PD: If you want to see the complete function, it's available at pastebin.
INSERT INTO table (id,a,b,c) VALUES (5454,1,2,3)
ON DUPLICATE KEY
UPDATE table SET foo WHERE id=xyz;
Set indexes in the DB
use mysqli instead of mysql
collect all the stuff you want to insert and do it with a prepared statement / stored procedure like here How to insert an array into a single MySQL Prepared statement w/ PHP and PDO
don't do 500 SELECTs, simple get the entire database and work through it via a foreach/while loop, checking for the stuff you need
use a construct like above
Important: For the above statement the column id should have an unique index !!!
Wrap INSERTs into transaction and don't worry, mysql_insert_id() is completely safe unless you switch to another database connection.
It is also possible to wrap all your queries to a transaction in result of massive speed improvement.