Been trying to wrap my head around this one, but have been unsuccessful.
Basically I am trying to create a database containing only two tables.
The first table is the logins table, and contains columns:
User ID
Username
Password
First Name
Last Name
The second table is the vote table, and contains columns:
User ID
Vote 1
Vote 2
Vote 3
etc. etc.
Is there anyway that I can relate these tables with the User ID as a primary key, that can cascade update/delete, so that when I add an entry into the logins table, it auto creates an entry in the votes table with the same User ID, and default value for all the vote columns?
I could add the votes to the main table, but wanted to seperate them out as much as possible, as not everyone will be creating votes.
Many thanks
Eds
If you want to cascade updates, you'll need to use a transaction:
START TRANSACTION;
INSERT INTO logins (username, passhash, salt, `first name`, `last name`)
VALUES ('$username', SHA2(CONCAT('$salt','$password'),512), '$salt',
'$firstname', '$lastname');
SELECT #userid:= LAST_INSERT_ID();
INSERT INTO votes (userid) VALUES (#userid);
COMMIT;
Make sure you have default values set in the table definition of the votes table.
Note the use of salted hashed passwords.
You could specify an insert trigger on the logins table.
This will execute each time a row is inserted into the logins table. You can specify what you'd like the trigger to do. In this case you can create the trigger to insert a single row into your vote table using the id just created in the login table along with your default values.
So something like:
CREATE TRIGGER logins_default_vote AFTER INSERT ON logins
FOR EACH ROW
INSERT INTO vote (UserID,Vote1,Vote2,Vote3)
VALUES (NEW.UserId,'vote1 default','vote2 default','vote3 default');
Related
I am totally new to PHP and I'm trying to create a registration page. To register, a user has to create a username, password, email, which are put into a table called users.
They also enter address details which is put into a table called customer_info.
In both tables I have created an auto increment, primary key called 'user_id'.
When the form is completed it fills out and enters the data, but the data is not banded and so there are two user_id, one in users and one in customer_info.
First I create values (from the post) that have been entered and assign them to variables. Then I put the variables into my table using the following query:
$result = mysql_query(
"INSERT INTO `users`(username, password, email) VALUES ('$value1', '$value2','$value3')"
);
and
$result = mysql_query(
"INSERT INTO `customer_info`(firstname, lastname, b_add_num, b_add_road, b_add_town, b_add_pc, p_add_num, p_add_road, p_add_town, p_add_pc) VALUES ('$value4','$value5','$value6','$value7','$value8','$value9','$value10','$value11','$value12','$value13')"
);
How would I set it so that it creates only one user id for both tables (making a connection between the sets of data)?
Is there something missing in my query, that should connect the tables?
Before anything, you should not use mysql_* extension anymore. Go towards PDO or mysqli
Your technique generates two different unique ids. The point is to have only one, so that it can be unique, and link information on that unique id.
The users table is the one with that unique id, user_id, which is your auto_increment column. The customer_info table can also have a info_id unique column, but must contain a user_id column, which will contain the user's user_id, linking the rows together.
It would also be a great moment to add a foreign key to your tables so that integrity of the data won't be compromised.
so after this query:
$result = mysql_query(
"INSERT INTO `users`(username, password, email) VALUES ('$value1', '$value2','$value3')"
);
get the insert id:
$id = mysql_insert_id();
then run your other query with it:
$result = mysql_query(
"INSERT INTO `customer_info`(user_id,firstname, lastname, b_add_num, b_add_road, b_add_town, b_add_pc, p_add_num, p_add_road, p_add_town, p_add_pc) VALUES ('$id','$value4','$value5','$value6','$value7','$value8','$value9','$value10','$value11','$value12','$value13')"
);
I would configure USER_ID as an AUTO_INCREMENT column only in Users table, insert the data into Users table first, then get the ID of the user inserted, using the mysql_insert_id ($connection_id); and use that while inserting data into Customer_Info table. This way, you can leverage the ID generation (sequence) feature of MySQL as well.
I want to import records from Gmail into a table, and I do not need duplicates for each account.
Description:
I have a table named list with definition below:
id int(11),
account_id int(11),
email varchar(255),
phone varchar(30),
primary key(id),
FOREIGN KEY (account_id) REFERENCES accounts (id)
This table holds records for different accounts and an email can be considered valid for two or more accounts. This means that an email can repeat in a table but can only appear once for each account_id.
I imported my contacts from Gmail (which is above 700 contacts and other users may have more than that).
The challenge:
I have an option of running two queries (one to check if email or phone exists, the second to insert record) for each record which in my case is 1,400 SQL queries to enable me insert all imported records, ensuring there are no duplicates for each account_id in the list table.
I have looked at MySQL IGNORE and similar keywords like ON DUPLICATE KEY UPDATE but they do not seem to work in this scenario as I cannot make the email and phone columns unique as they can contain duplicate content.
What is the best way of inserting these 700 records ensuring that the email and phone are not repeated for each account_id without having to run 1,400 queries?
QUESTION UPDATE:
I do not think INSERT IGNORE CAN WORK HERE FOR THE FOLLOWING REASONS:
I cannot make email and phone unique columns
The phone number may be empty but with an email entry, this may break the unique pattern
QUESTION ILLUSTRATION
I have two offices using the table to store their customer records. Someone can be a customer to both offices. This means his record can appear twice in the table but can only appear once for each account_id in the table.
The challenge now is to insert several records into the table ensuring that a record does not repeat for each account_id.
What you are trying to achieve is not very clear to me, but it looks very much like you just need to add some two-columns unique constraints.
an email must be unique for one given account_id:
ALTER TABLE your_table ADD UNIQUE (account_id, email);
a phone number must be unique for one given account_id:
ALTER TABLE your_table ADD UNIQUE (account_id, phone);
Both indexes may exist at the same time on your table. Either could raise a "duplicate-key violation" error, and would trigger the IGNORE or the ON DUPLICATE clauses of your insertions.
That being said, there is an issue in your structure. You are about to duplicate your customers' details for each account_id they are in business with.
You should have a customers table that contains all your customer's contact details (and only that), another accounts table -- your "offices", if I understand it right -- and finally one relation table to model the n-n relationship between customers and accounts:
CREATE TABLE customers_accounts (
customer_id INT NOT NULL,
account_id INT NOT NULL,
PRIMARY KEY (customer_id, account_id),
FOREIGN KEY (customer_id) REFERENCES customers(id)
FOREIGN KEY (account_id) REFERENCES accounts(id)
);
You had the answer: use "INSERT IGNORE" but what you probably didn't do is add a composite unique index (mentioned by RamdomSeed above), and/or set blank fields to NULL.
1) Create composite index, using the account id. This means that the email must be unique for that user.
ADD UNIQUE(account_id, email)
2) Regarding the phone "may be blank" set this to NULL when blank. Unique indexes ignore NULLS. (A small gotcha, but probably plays in your favour here, and why it's like that. You can then also add
ADD UNIQUE(account_id, phone)
(Aside: general advice is that you don't usually have multiple uniques on a table as it can get confusing and messy, but it might be what you need and it's fine - so long as you can handle the logic)
Seems like you could use INSERT IGNORE assuming AccountId is your unique identifier:
INSERT IGNORE INTO table
SET field = someValue,
anotherfield = someothervalue
If however you can have the same accounts with multiple emails, then this may not be what you're looking for.
So it sounds like you're using a scripting language (php seems to be popular with mysql) to store an array of contacts from gmail?
If so, this insert statement will insert the record if the account id doesn't exist in the table already -- this uses an Outer Join with a Null check, but you can also use Not In or Not Exists as well:
Insert Into YourTable (Id, AccountId, Email, Phone)
Select t.Id, t.AccountId, t.Email, t.Phone
From (Select 1 Id, 1 AccountId, 'someemail' Email, 'somephone' Phone) t
Left Join YourTable t2 On t.AccountId = t2.AccountId
Where t2.AccountId Is Null
EDIT:
Assuming I'm understanding the comments, then just add to the Outer Join:
Insert Into YourTable (Id, AccountId, Email, Phone)
Select t.Id, t.AccountId, t.Email, t.Phone
From (Select 1 Id, 1 AccountId, 'someemail' Email, 'somephone' Phone) t
Left Join YourTable t2 On t.AccountId = t2.AccountId
And (t.email = t2.email Or t.phone = t2.phone)
Where t2.AccountId Is Null
This should ensure no accounts get reinserted if they have a matching phone or email.
Insert Into YourTable (Id, Account_Id, Email, Phone)
Select a.id, a.Account_Id, a.Email, a.Phone
From (Select t.id, t.Account_Id, t.Email, t.Phone from t
group by account_id,email,phone )a;
Suggest to import the records into a temp table (t). Then only filter the records into another table (yourtable) ie remove the duplicate as you like.
I have a table name Users and a table name Application.
I want to insert 3 data into 3 columns (id,password,privilege) at Users table.
How do i extract 2 data from Application table (email_address,password) then i add own data in privilege column at Users table.
Sorry if this is confusing.
You can use the following query:
INSERT INTO `Users` (id, password, privilege)
SELECT email_address, password, 'privileges' FROM `Application`
Where privileges stands for the user privileges
Lets say i got two tables in mysql.
1. person (id, name, lastname) - Image
2. someothertable (id, name, lastname, action, quantity) - image
I wanted to ask, if its really bad practice, to update both tables at once? For example if someone updates the last name of Robert Jackson to "Smith" then do 2 queries:
mysql_query("UPDATE person SET lastname = '$lastname' WHERE id = '$id'");
mysql_query("UPDATE someothertable SET lastname = '$lastname' WHERE name = '$name' AND lastname = '$oldlastname'");
Assuming for now, you wont meet 2 same names and surnames (its just an example).
Is it strongly recommended, to join those two tables when displaying data from tables, and change last name only in person table?
I didn't have need to use join before (never had databases big enough), and I just started to wonder if there is another way to do this (than 2 queries). Using join will require some code changing, but i am ready to do it, if its right thing to do.
Using a join is not a function of how big your databases are, it's about normalization and data integrity. The reason you would have lastname in only one table is so that there's no need to worry about keeping values in sync. In your example, if those calls are in a single transaction, then they should stay in sync. Unless one of them is changed somewhere else, or manually in the database.
So an option for you would be to have these tables:
person (id, name, lastname)
someothertable (id, person_id, action, quantity)
Instead of using 2 update, you can use trigger : Tutorial here
One option would be to make someothertable have a foreign key constraint on the lastname field in Person. You could apply an update trigger so it would automatically cascade.
Here is an example below:
Alter table someothertable add constraint foreign key (lastname) references Person (lastname) on delete cascade on update cascade;
A generic version of that can be seen below:
Alter table [table-name] add constraint foreign key (field-in-current-table) references [other-table-name] (field-in-other-table) on delete cascade on update cascade;
This can be applied to any field in any table. You can then set the triggers to be appropriate for you. Here is a reference link.
Have you considered normalization?
Another option would be to assign each person in the Person table a uniqueID (i.e. PersonID). Now in all your other tables you where you reference a person you reference them by the unique id. This adds many advantages:
1) It keeps the data normalized
2) It maintains data integrity
3) No need for updates, triggers, or cascades
4) A change would only be required in one place
Hope this helps. Best of luck!
I have a site that is essentially a collection of links. A mysql database which stores users, links and votes. My links table has two foreign keys, user_id and vote_id. When a link is inserted into the database it will start with one vote so that means I need to insert a row into the votes table but they essentially depend on one another to exist. I need the ID of the links for the foreign key of the votes table and vice versa. My current "plan" is to insert a links row with a vote_id of 0, select the same row to get it's ID and then insert a votes row using the links row id as it's foreign key, select it's ID and update my original links row. This seems really inefficient but I need to make sure users votes are recorded for time keeping and eliminating duplicate votes. Am I going about this the wrong way?
In PHP, you can use mysql_insert_id:
mysql_query("INSERT INTO mytable (product) values ('kossu')");
printf("Last inserted record has id %d\n", mysql_insert_id());
You could use this to get the row ID of the newly inserted link.
Assuming one vote can only belong to one link, the links table should not have a vote_id column. So you shouldn't need the identity of the newly inserted vote.