don't repeat entry row from two different table - mysql

i created two database (php using XAMPP) one for employee (id, name) and another for administrator(id, name).
the id in the two tables are primary key, i need to build a relation between the two table where id don't repeat .for example :admin(1,a)uses id = 1 which should not be used in the employee table
please help

The normative approach to this problem is to use a single table. That makes it very easy to keep the id values distinct.
You can include a discriminator column that indicates whether a row represents an "employee" or an "administrator". In your example, there's two possible values.
CREATE TABLE employee
( id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT COMMENT 'pk'
, ename VARCHAR(50) NOT NULL
, admin TINYINT(1) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'boolean'
)
Some example data, to illustrate:
id ename admin
--- ---------------- -------
42 Barney Rubble 0
43 Fred Flintstone 0
17 Mr. Slate 1
Sample queries:
-- select "employee" rows
SELECT id, ename FROM employee WHERE admin=0
-- select "administrator" rows
SELECT id, ename FROM employee WHERE admin
If you need two separate tables, that you asked about
Bottom line is that there is no declarative constraint available in MySQL that will enforce the id values between the two tables to be "distinct" from one another.
To do that, you would have to "roll your own" solution. And that solution is not trivial, it can be rather involved.
There are some solutions to simpler problems, automatically generating unique id values. But to actually enforce uniqueness, there is no simple way to do that.
Is your goal to just enforce a constraint, such that INSERT and UPDATE statements will throw an error if they attempt to violate the constraint, you are going to need to write triggers.

Related

Uncaught mysqli_sql_exception: Subquery returns more than 1 row

I have two tables one with names and telnumbers the second with calls
addressbook name(VARCHAR) number(VARCHAR)
calls date(DATE) number(VARCHAR) name(VARCHAR)
I want to update the names column in the calls table with the entries in the addressbook for the respective
UPDATE calls
SET name = ( SELECT name FROM addressbook WHERE number = calls.number )
WHERE DATE = "2020.01.01"
ORDER BY DATE
And I get Uncaught mysqli_sql_exception: Subquery returns more than 1 row but there are no doublette in the addressbook I checked it several times.
The only way your update statement can fail with
Subquery returns more than 1 row
is if there is at least one calls row whose number appears more than once in addressbook. You can find them with this query:
select number, count(*)
from addressbook
group by number
having count(*) > 1;
Let's say you have these two rows in addressbook:
name number
------ ------
fred 123
barney 123
And let's say this is the row in calls:
date name number
---------- ---- ------
2020.01.01 null 123
When you execute Stefano's update statement, the limit clause is not deterministic because there's no associated order by clause in the subquery. Nor is there any attribute common to calls and addressbook that would make it meaningful. The order by clause on the update is irrelevant. Therefore, you cannot guarantee which name will be assigned to the calls row. This is the point I was trying to make in my comment to Stefano's answer.
If the design of the system is to allow a number to be owned by multiple people over time (which they are of course), then your schema is not complete. And if that's true, then addressbook needs an effective date for the owner of the number.
If the design of the system is not to allow a number to be owned by multiple people over time, then you must delete the duplicate rows.
In either case, you need to do two things:
employ declarative referential integrity constraints so you don't run afoul again
stop updating calls: either insert (not update) the name or remove the column entirely
If I were to implement the tables of a telephony system, I would start with something like this:
create table PERSON (
PERSON_ID integer not null primary key,
NAME varchar(100) not null /*lots of other columns*/);
create table PERSON_PHONE (
PERSON_PHONE_ID integer not null primary key,
PERSON_ID integer not null,
PHONE_NUM varchar(30) not null,
CONTRACTED date not null, /*lots of other columns*/
unique (PERSON_ID, PHONE_NUM, CONTRACTED),
foreign key (PERSON_ID) references PERSON(PERSON_ID));
create table PHONE_CALL (
START_DATE date not null,
END_DATE date not null,
PERSON_PHONE_ID integer not null,
primary key (PERSON_PHONE_ID, START_DATE),
foreign key (PERSON_PHONE_ID) references PERSON_PHONE(PERSON_PHONE_ID));
It is true that sometimes, for the sake of making queries finish faster using fewer resources, people will sometimes denormalize a schema to decrease the number of join operations that would otherwise be required. Denormalization requires careful consideration.
The error is self explanatory, the sub query returns more than one row, a quick solution is:
SELECT name FROM addressbook WHERE number = calls.number LIMIT 1
if this solve the issue than the query return more than a row. If you need to returns just a row without using LIMIT 1 you should review your query adding more constraints or define a primary key for the addressbook table and continuing use your subquery as it is. This is on you.

How to use auto-increment for alpha numeric value in database

I am working in a project. In my project database, I have student and trainer. I need to use auto-increment with alpha-numeric for student id and trainer id.
For example:
student id should be automatically incremented as STU1,STU2....
trainer id should be automatically incremented as TRA1,TRA2....
I am using MySQL as my DB.
If it is possible, please give solution for other databases like oracle, Sql server.
MySQL does not have any built in functionality to handle this. If the value you want to add on the front of the auto incremented id is always the same, then you should not need it at all and just add it to the front in your SELECT statement:
SELECT CONCAT('STU', CAST(student_id AS CHAR)) AS StudentID,
CONCAT('TRA', CAST(trainer_id AS CHAR)) AS TrainerID
FROM MyTable
Otherwise the following would work for you:
CREATE TABLE MyTable (
student_id int unsigned not null auto_increment,
student_id_adder char(3) not null
trainer_id int unsigned not null auto_increment,
trainer_id_adder char(3) not null
)
The SELECT to pull them together might look like the following:
SELECT CONCAT(student_id_adder, CAST(student_id AS CHAR)) AS StudentID,
CONCAT(trainer_id_adder, CAST(trainer_id AS CHAR)) AS TrainerID
FROM MyTable
You are mixing two different concepts here. The autoincrement feature is for ID based database tables.
You can build a student table where each student gets an ID, which can be a number or something else and will probably be printed in the student card. Such a table would look like this:
Table student
student_card_id
first_name
last_name
...
There can be other tables using the student_card_id. Now some people say this is good. Students are identified by their card IDs, and these will never change. They use this natural key as the primary key in the table. Others, however, say that there should be a technical ID for each table, so if one day you decide to use different student numbers (e.g. STUDENT01 instead of STU01), then you would not have to update the code in all referencing tables. You would use an additional technical ID as shown here:
Table student
id
student_card_id
first_name
last_name
...
You would use the ID as primary key and should use the auto increment feature with it. So student STU01 may have the technical ID 18654; it just doesn't matter, for it's only a technical reference. The student card will still contain STU01. The student won't even know that their database record has number 18654.
Don't mix these two concepts. Decide whether you want your tables to be ID based or natural key based. In either case you must think of a way to generate the student card numbers. I suggest you write a function for that.

Best Practice: find row for unique id from multiple tables

our database contain 5+ tables
user
----------
user_id (PK) int NOT NULL
name varchar(50) NOT NULL
photo
--------
photo_id (PK) int NOT NULL
user_id (FK) int NOT NULL
title varchar(50) NOT NULL
comment
-------
comment_id (PK) int NOT NULL
photo_id int NOT NULL
user_id int NOT NULL
message varchar(50) NOT NULL
all primary key id's are unique id's.
all data are linked to http://domain.com/{primary_key_id}
after user visit the link with id, which is unique for all tables.
how should i implement to find what table this id belongs to?
solution 1
select user_id from user where user_id = {primary_key_id}
// if not found, then move next
select photo_id from photo where photo_id = {primary_key_id}
... continue on, until we find which table this primary key belongs to.
solution 2
create object table to hold all the uniqe id and there data type
create trigger on all the tables for AFTER INSERT, to create row in object table with its data type, which was inserted to a selected table
when required, then do select statement to find the table name the id belongs to.
second solution will be double insert. 1 insert for row to actual table with complete data and 2 insert for inserting unique id and table name in object table, which we created on step 1.
select type from object_table where id = {primary_key_id}
solution 3
prepend table name + id = encode into new unique integer - using php
decode id and get the original id with table name (even if its just as number type)
i don't know how to implement this in php, but this solution sounds better!? what are your suggestion?
I don't know what you mean by Facebook reference in the comments but I'll explain my comment a little further.
You don't need unique ID's across five DB tables, just one per table. You have couple of options how to create your links (you can create the links yourself can you?):
using GET variables: http://domain.com/page.html?pk={id}&table={table}
using plain URL: http://domain.com/{id}{table}
Depending on the syntax of the link you choose the function to parse it. You can for example use one or both of the following:
http://php.net/manual/en/function.explode.php
http://www.php.net/manual/en/function.parse-url.php
When you get the simple model working you may add encoding/decoding/hashing functions. But do you really need them? And in what level? (I have no experience in that area so I'll shut up now.)
Is it actually important to maintain uniqueness across tables?
If no, just implement the solution 3 if you can (e.g. using URL encoding).
If yes, you'll need the "parent" table in any case, so the DBMS can enforce the uniqueness.
You can still try to implement the solution 3 on top of that,
or add a type discriminator1 there and you'll be able to (quickly) know which table is referenced for any given ID.
1 Take a look at the lower part of this answer. This is in fact a form of inheritance.

Make a unique select statement in MySQL

I have a select statement which, at least should, return only unique userId. If this does not happen and userIds are double a user did input something illegal.
To illustrate we use a simple SELECT userId, name, FROM USER. Now, usually you will make the userId unique/primarykey at the table level. Just for the sake of the example we don't.
The expected result would be:
userId name
---------------
1 Roel
2 Joe
3 John
But the result is something like
userId name
---------------
1 Roel
1 Roel
2 Joe
3 John
3 John
Is there possiblity to make the query in such a way that it would give an error when the result contains more than one the userIds?
Just add DISTINCT. And it will make your rows unique.
SELECT DISTINCT userId, name
FROM USER
By definition, the DISTINCT keyword can be used to return only distinct (different) values.
UPDATE 1
The reason why is that you didn't specify a constraint on your table. Make a table definition like this.
CREATE TABLE userList
(
ID INT NOT NULL AUTO_INCREMENT,
NAME VARCHAR(50) NOT NULL,
CONSTRAINT id_PK PRIMARY (ID),
CONSTRAINT name_unique UNIQUE (NAME)
)
when you don't want ID to be auto_incremented, you can remove the AUTO_INCREMENT word on the table definition, or create a table definition like this
CREATE TABLE userList
(
ID INT NOT NULL,
NAME VARCHAR(50) NOT NULL,
CONSTRAINT id_PK PRIMARY (ID),
CONSTRAINT name_unique UNIQUE (ID, NAME)
)
SELECT
UserId, COUNT(*)
FROM
User
GROUP BY
UserId
HAVING
COUNT(*) > 1
Any records returned from this will be those for which there is erroneous data. That would be the simplest way to identify when to raise an error, but it wouldn't simply raise one for you. You could wrap the above query into a procedure, and use some logic to determine whether to raise an error or run the main query.
Well, I guess this is importent during registration... so just count() the hits of a given username before you allow an INSERT.
Secondly make the name column UNIQUE and then you get the right error upon INSERT
Another solution is
SELECT *
FROM User
UNION
SELECT *
FROM User
The advantage of this is that you don't have to list the variables in SELECT. Usually, it is bad not to write explicitly the column names but I think this case is one of the rare cases where it makes sense.

Database design - primary key naming conventions

I am interested to know what people think about (AND WHY) the following 3 different conventions for naming database table primary keys in MySQL?
-Example 1-
Table name: User,
Primary key column name: user_id
-Example 2-
Table name: User,
Primary key column name: id
-Example 3-
Table name: User,
Primary key column name: pk_user_id
Just want to hear ideas and perhaps learn something in the process :)
Thanks.
I would go with option 2. To me, "id" itself seems sufficient enough.
Since the table is User so the column "id" within "user" indicates that it is the identification criteria for User.
However, i must add that naming conventions are all about consistency.
There is usually no right / wrong as long as there is a consistent pattern and it is applied across the application, thats probably the more important factor in how effective the naming conventions will be and how far they go towards making the application easier to understand and hence maintain.
I always prefer the option in example 1, in which the table name is (redundantly) used in the column name. This is because I prefer to see ON user.user_id = history.user_id than ON user.id = history.user_id in JOINs.
However, the weight of opinion on this issue generally seems to run against me here on Stackoverflow, where most people prefer example 2.
Incidentally, I prefer UserID to user_id as a column naming convention. I don't like typing underscores, and the use of the underscore as the common SQL single-character-match character can sometimes be a little confusing.
ID is the worst PK name you can have in my opinion. TablenameID works much better for reporting so you don't have to alias a bunch of columns named the same thing when doing complex reporting queries.
It is my personal belief that columns should only be named the same thing if they mean the same thing. The customer ID does not mean the same thing as the orderid and thus they should conceptually have different names. WHen you have many joins and a complex data structure, it is easier to maintain as well when the pk and fk have the same name. It is harder to spot an error in a join when you have ID columns. For instance suppose you joined to four tables all of which have an ID column. In the last join you accidentally used the alias for the first table and not the third one. If you used OrderID, CustomerID etc. instead of ID, you would get a syntax error because the first table doesn't contain that column. If you use ID it would happily join incorrectly.
I tend to go with the first option, user_id.
If you go with id, you usually end up with a need to alias excessively in your queries.
If you go with more_complicated_id, then you either must abbreviate, or you run out of room, and you get tired of typing such long column names.
2 cents.
I agree with #InSane and like just Id. And here's why:
If you have a table called User, and a column dealing with the user's name, do you call it UserName or just Name? The "User" seems redundant. If you have a table called Customer, and a column called Address, do you call the column CustomerAddress?
Though I have also seen where you would use UserId, and then if you have a table with a foreign key to User, the column would also be UserId. This allows for the consistency in naming, but IMO, doesn't buy you that much.
In response to Tomas' answer, there will still be ambiguity assuming that the PK for the comment table is also named id.
In response to the question, Example 1 gets my vote. [table name]_id would actually remove the ambiguity.
Instead of
SELECT u.id AS user_id, c.id AS comment_id FROM user u JOIN comment c ON u.id=c.user_id
I could simply write
SELECT user_id, comment_id FROM user u JOIN comment c ON u.user_id=c.user_id
There's nothing ambiguous about using the same ID name in both WHERE and ON. It actually adds clarity IMHO.
I've always appreciated Justinsomnia's take on database naming conventions. Give it a read: http://justinsomnia.org/2003/04/essential-database-naming-conventions-and-style/
I would suggest example 2. That way there is no ambiguity between foreign keys and primary keys, as there is in example 1. You can do for instance
SELECT * FROM user, comment WHERE user.id = comment.user_id
which is clear and concise.
The third example is redundant in a design where all id's are used as primary keys.
OK so forget example 3 - it's just plain silly, so it's between 1 and 2.
the id for PK school of thought (2)
drop table if exists customer;
create table customer
(
id int unsigned not null auto_increment primary key, -- my names are id, cid, cusid, custid ????
name varchar(255) not null
)engine=innodb;
insert into customer (name) values ('cust1'),('cust2');
drop table if exists orders;
create table orders
(
id int unsigned not null auto_increment primary key, -- my names are id, oid, ordid
cid int unsigned not null -- hmmm what shall i call this ?
)engine=innodb;
insert into orders (cid) values (1),(2),(1),(1),(2);
-- so if i do a simple give me all of the customer orders query we get the following output
select
c.id,
o.id
from
customer c
inner join orders o on c.id = o.cid;
id id1 -- big fan of column names like id1, id2, id3 : they are sooo descriptive
== ===
1 1
2 2
1 3
1 4
2 5
-- so now i have to alias my columns like so:
select
c.id as cid, -- shall i call it cid or custid, customer_id whatever ??
o.id as oid
from
customer c
inner join orders o on c.id = o.cid; -- cid here but id in customer - where is my consistency ?
cid oid
== ===
1 1
2 2
1 3
1 4
2 5
the tablename_id prefix for PK/FK name school of thought (1)
(feel free to use an abbreviated form of tablename i.e cust_id instead of customer_id)
drop table if exists customer;
create table customer
(
cust_id int unsigned not null auto_increment primary key, -- pk
name varchar(255) not null
)engine=innodb;
insert into customer (name) values ('cust1'),('cust2');
drop table if exists orders;
create table orders
(
order_id int unsigned not null auto_increment primary key,
cust_id int unsigned not null
)engine=innodb;
insert into orders (cust_id) values (1),(2),(1),(1),(2);
select
c.cust_id,
o.order_id
from
customer c
inner join orders o on c.cust_id = o.cust_id; -- ahhhh, cust_id is cust_id is cust_id :)
cust_id order_id
======= ========
1 1
2 2
1 3
1 4
2 5
so you see the tablename_ prefix or abbreviated tablename_prefix method is ofc the most
consistent and easily the best convention.
I don't disagree with what most of the answers note - just be consistent. However, I just wanted to add that one benefit of the redundant approach with user_id allows for use of the USING syntactic sugar. If it weren't for this factor, I think I'd personally opt to avoid the redundancy.
For example,
SELECT *
FROM user
INNER JOIN subscription ON user.id = subscription.user_id
vs
SELECT *
FROM user
INNER JOIN subscription USING(user_id)
It's not a crazy significant difference, but I find it helpful.