I have already asked this but did not get what I am looking for, I have many tables with column id set to auto-increment and primary key.
Table1
id, title, condition...
Table2
id, title, condition...
And I have a search box where I search for products and my query is like
$stmt = $mysqli->prepare("select * from table1 where title Like ? or id = ? ");
$stmt->bind_param('ss', $searchterm, $searchterm");
$stmt->execute();
$stmt = $mysqli->prepare("select * from table2 where title Like ? or id = ? ");
$stmt->bind_param('ss', $searchterm, $searchterm");
$stmt->execute();
So if I search for "1" then I will get all the products with id or title 1 but what I want is to have a unique identfier for each row. How can I accomplish this? As I am working with products, there should be a unique id for each product.
Or could it be possible to have a alphabet in front of the id, something like T1, T2, T3?
If you were using the Oracle table server, you'd use a database entity called a SEQUENCE to get a data-base-wide unique id value for your tables.
It's easy enough to emulate SEQUENCE entities in MySQL, though, even if it's a little clunky and not quite as space-efficient.
First, create yourself a table like this.
CREATE TABLE sequence (
sequence_id BIGINT NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`sequence_id`)
)
Then, create your other tables, the ones which will use these unique sequence_id values. Here's an example:
CREATE TABLE gadget (
sequence_id BIGINT NOT NULL,
gname VARCHAR(20) DEFAULT NULL,
gvalue VARCHAR(20) DEFAULT NULL,
PRIMARY KEY (sequence_id)
)
Here's another:
CREATE TABLE widget (
sequence_id BIGINT NOT NULL,
wname VARCHAR(20) DEFAULT NULL,
wvalue VARCHAR(20) DEFAULT NULL,
PRIMARY KEY (sequence_id)
)
Then, whenever you insert a row into your other tables, do it like this:
INSERT INTO sequence () VALUES() ;
INSERT INTO widget (sequence_id, wname, wvalue)
VALUES (LAST_INSERT_ID(), 'whatever', 'you_want');
or, for the other example table,
INSERT INTO sequence () VALUES() ;
INSERT INTO gadget (sequence_id, gname, gvalue)
VALUES (LAST_INSERT_ID(), 'another', 'gadget');
The trick is this: when you insert each (seemingly empty) row into the sequence table it updates the auto-increment sequence_id field. Then, when you use the LAST_INSERT_ID() function it retrieves the most-recently inserted value of that sequence_id.
Be very careful to keep your two INSERT INTO statements consecutive, or this will stop working properly.
This works even if many different clients of the database server are doing the inserts, for two reasons;
auto-increment is thread-safe. No two sequence numbers can be the same.
LAST_INSERT_ID() values are maintained one for each distinct connection to the MySQL database. Different programs (or different threads in a multi-threaded web application) each have their own connections, so they each have their own values of LAST_INSERT_ID().
By the way, I used bigint data for the sequence, but int will work just as well.
Related
I have a table where I log members.
There are 1,486,044 records here.
SELECT * FROM `user_log` WHERE user = '1554143' order by id desc
However, this query takes 5 seconds. What do you recommend ?
Table construction below;
CREATE TABLE IF NOT EXISTS `user_log` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user` int(11) NOT NULL,
`operation_detail` varchar(100) NOT NULL,
`ip_adress` varchar(50) NOT NULL,
`l_date` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
COMMIT;
For this query:
SELECT * FROM `user_log` WHERE user = 1554143 order by id desc
You want an index on (user, id desc).
Note that I removed the single quotes around the filtering value for user, since this column is a number. This does not necessarily speeds things up, but is cleaner.
Also: select * is not a good practice, and not good for performance. You should enumerate the columns you want in the resultset (if you don't need them all, do not select them all). If you want all columns, since your table has not a lot of columns, you might want to try a covering index on all 5 columns, like: (user, id desc, operation_detail, ip_adress, l_date).
In addition to the option of creating an index on (user, id), which has already been mentioned, a likely better option is to convert the table to InnoDB as create an index only on (user).
I'm using php and i have a table that have 2 column of varchar , one is used for user identification, and the other is used for page name entry.
they both must be varchar.
i want to insert ignore data when user enter a page to know if he visited it or not, and i want to fetch all the rows that the user have been in.
fetch all for first varchar column.
insert if not exist for both values.
I'm hoping to do it in the most efficient way.
what is the best way to insert without checking with another query if exist?
what is the best way other then:
SELECT * FROM table WHERE id = id
to fetch when the column needed is varchar?
You should consider a normalized table structure like this:
CREATE TABLE user (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100)
);
CREATE TABLE page (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100)
);
CREATE TABLE pages_visted (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
user_id INT UNSIGNED,
page_id INT UNSIGNED,
UNIQUE KEY (user_id, page_id)
);
INSERT IGNORE INTO pages_visted (user_id, page_id) VALUES (:userId, :pageId);
SELECT page_id FROM pages_visted WHERE user_id = :userId;
I think you want to implement a composite primary key.
A composite primary key tells MySQL that you want your primary key to be a combination of fields.
More info here: Why use multiple columns as primary keys (composite primary key)
I don't know of a better option for your query, although I can advise, if possible:
Define columns to be NOT NULL. This gives you faster processing and requires less storage. It will also simplify queries sometimes because you don't need to check for NULL as a special case.
And with variable-length rows, you get more fragmentation in tables where you perform many deletes or updates due to the differing sizes of the records. You'll need to run OPTIMIZE TABLE periodically to maintain performance.
I have a create database and have about 8 tables in Database also created Primary keys and foreign-keys in appropriate tables. But when I insert data in primary-table, my other table doesn't show updated data.
I mean, say I have a table which has data for names like ;
N is (name)
N1 = George, N2 = Ross, N3 = Rim ...etc now that means i have Primary key N1,N2,N3 etc..
Now, when I insert this primary keys in others table it should shows me name like George, ross and rim instead of primary-key number it self(N1,N2,N3).
How can I get names instead PK itself?
You are misunderstanding the concept of keys in relational databases. Keys are there, not to copy data from similar tables but to show the relations between data in different tables. They help to understand how the data between different tables is related - that is where the name "relational database" comes from. They also speed up querying of that data if indexed.
You can read more about the usage of keys here: Keys and normalization
I am still unclear on what exactly you want to do with the database. but let me demonstrate you on the basic of database and how you should be using it. Consider a table users where you will be storing the data related to user.
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
`email` varchar(50) DEFAULT NULL,
`phone` varchar(30) DEFAULT NULL,
PRIMARY KEY (`id`),
);
the column id holds the primary key and have an attribute called auto_increment, now what this means is every time you insert a record to this table the id attribute gets incremented and you don't have to worry about inserting any value in this column because your database will take care of that. for example take a look at insert query below.
INSERT INTO users(name,email,phone) VALUES('First Name', 'first#domain.com', '9999999999');
INSERT INTO users(name,email,phone) VALUES('Second Name', 'second#domain.com', '8888888888');
INSERT INTO users(name,email,phone) VALUES('Third Name', 'third#domain.com', '2222222222');
INSERT INTO users(name,email,phone) VALUES('Fourth Name', 'fourth#domain.com', '3333333333');
did you see you did not insert any id here. this is because it is database who will handle the logic. now the first record will hold the value 1 the second will have 2 the third one 3 and the fourth one 4 and so on.
hope this helps you.
I have a table in a mySQL database we'll call 'tbl' where the fields are:
id, userID, favorite, emailID
The id is auto incremental. The userID stores an integer. The favorite is either yes or no. The emailID stores an integer.
I am programing in PHP and would like to have one query used to query the database that checks if the userID and emailID combination exists. If it does then update the favorite field with a yes or no value that comes from a form that is passed into the query dynamically. If it does not exist then insert the combination into the database.
Therefore if I had:
<?php
$userID = 34;
$emailID = 395;
$favorite = "yes"; // could be yes or no.
I don't believe the query below is correct but gets the idea of what I am trying to do:
IF NOT EXISTS
(SELECT userID, favorite, emailID
FROM tbl
WHERE ((userID = '$userID')and(emailID = '$emailID'))
INSERT INTO tbl (userID, favorite, emailID) VALUES ('$userID', '$favorite', '$emailID')
ELSE UPDATE tbl
SET favorite = '$favorite'
WHERE ((userID = '$userID')and(emailID = '$emailID'))
(please know that I know that entering values into a query like this is a security risk, this is only to help explain my question.)
What is the best way to write the query? Can it be written with one query?
It can't be written as a single query, because the primary key isn't the two columns you're looking for - it's the id column only.
If userid and emailid are unique pairs, they should be the primary key for the table -- not the id value. ORMs typically prefer that a primary key be single column for making query construction easier but the approach suffers on performance. Anything requiring more than one columns is generally referred to as a "composite" - primary key, unique constraint/index, foreign key, etc.
The ANSI means of doing this would be a MERGE statement, but MySQL doesn't support the syntax because it already has the ON DUPLICATE KEY UPDATE and REPLACE INTO to provide the same functionality.
I would drop the redundant id column and define the primary key as the combination of (userID, emailID), which means you have exactly one record for each different combination of the two fields, which seems to be what you want. Then you can use the REPLACE INTO command, which is equivalent to an INSERT but deletes any existing record if the primary key matches.
you can do it really simply in a single call - but sprocs are bad aren't they ??
drop procedure if exists insert_update_tbl;
delimiter #
create procedure insert_update_tbl
(
in p_userID int unsigned,
in p_emailID int unsigned,
out p_id int unsigned
)
proc_main:begin
set p_id = 0;
if exists (select 1 from tbl where userID = p_userID and emailID = p_emailID) then
update tbl set favorite = 1 where userID = p_userID and emailID = p_emailID;
leave proc_main;
end if;
insert into tbl (userID, emailID, favorite) values (p_userID, p_emailID, 0);
set p_id = last_insert_id();
end proc_main #
delimiter ;
Question on preventing duplicated entry in my simple web form.
My table record user input from a web form, and distinguished by date e.g. DATE(). How to prevent user with the same name to enter information twice in a single date, e.g. same username cannot be entered twice in the same date, but can be entered at other date?
Your table should have these:
create table tablename (
...
user_id bigint, -- or whatever
date_created date,
unique key(user_id, date_created)
...
);
You can simple create a composite primary key. For your case this means that your primary key must consists of a date field as well as the username field.
In several ways.
First, you can create index on your table. (i'm using simple table as an example).
CREATE TABLE `test` (
`id` INT NOT NULL ,
`name` VARCHAR( 255 ) NOT NULL ,
`date` DATE NOT NULL ,
PRIMARY KEY ( `id` )
) ENGINE = MYISAM;
ALTER TABLE `test` ADD UNIQUE (
`name` ,
`date`
);
This is MySQL way.
You also should make checks in PHP ,although you can do it when inserting (MySQL will return error and you can check it). But you can make additional SELECT before inserting (SELECT * from test WHERE name=USER AND date=DATE) and check record count. If it's more than 0, you show error.
When saving, you seldom should worry about one additional SQL. If you should, just check MySQL statement for errors (MySQL way :)).
Create a unique key on the user and date column
http://dev.mysql.com/doc/refman/5.1/en/create-table.html