Inserting unique records into MS access 2007 - mysql

So i have been looking around and not finding much. I appologize ahead of time because this is probably the wrong way to do this but it is what it is.
So i have to track class's that co-workers have completed. This is done through a excel sheet that feeds the MS access database. There is 3 fields that are supplied to me.
Full name, Course Name, and Completion Date.
I know that i dont have a primary key here so i am trying to create a query that will only append the unique records pulled from the excel sheet. I can do it based on a single field but need help making my query append it only when both the Full name and Course Name are not the same for example
Joe Somebody, Course#1, 14feb13
Joe Somebody, Course#2, 15feb13
Joe Somebody, Course#1, 15feb13
I need a query that will append the first 2 rows to a table but ignore the third one due to the person already completing course#1. this is what i have so far that basicly turns my name field into a Primary key.
INSERT INTO table [Full name], [Course], [Date]
SELECT excel_table.[Full name], excel_table.[Course], excel_table.[Date]
FROM excel_table
WHERE excel_table.[Full name] Not in (SELECT table.[Full Name] FROM table)
I also have some Is Not Null stuff at the end but i didnt think it would be relevent to the question.

The easiest way to do this so you do not get duplicates is to add an index. In this case, a composite primary key would seem to be the answer. Just select all of the fields you want included in the composite key and click the Primary Key button:
You will not be allowed nulls in any of the fields comprising the primary key, but as long as the combination of the fields is not matched, data in each of the fields can be repeated. So:
Joe Somebody, Course#1, 14feb13 <-- good
Joe Somebody, Course#2, 15feb13 <-- good
Joe Somebody, Course#1, 15feb13 <-- fails
Joe SomebodyElse, Course#1, 14feb13 <-- good
Now, if you run an ordinary append query build with the query design window, you will get an error if the record exists twice in the Excel import table or already exists in Access:

You don't actually need a composite primary key. In fact there are a few places in Access where you are encouraged to not use a composite primary key. You can create your Access table with a simple integer primary key:
create table CourseCompletions (
ID autoincrement primary key
, FullName varchar(100)
, CourseName varchar(100)
, CompletionDate date
);
Then you can gulp in all the data from the Excel file:
insert into CourseCompletions (
, FullName
, CourseName
, CompletionDate
) select
[Full name]
, [Course]
, [Date]
from excel_table;
This will give each row of your input Excel table a unique number and stash it in the Access table. Now you need to decide how you want to reject conflicting rows from your CourseCompletions table. (The following queries show only the records that you decide to not reject.) If you want to reject completions by the same person of the same course at a later date:
select
ID
, FullName
, CourseName
, min(CompletionDate)
from CourseCompletions
group by
ID
, FullName
, CourseName;
If you want to reject completions at an earlier date simply change the MIN to MAX.
If you want to reject any course completion that appeared earlier in the Excel table:
select
cc1.ID
, cc1.FullName
, cc1.CourseName
, cc1.CompletionDate
from CourseCompletions as cc1
inner join (
select
max(ID) as WantedID
, FullName
, CourseName
from CourseCompletions
group by FullName, CourseName
) as cc2
on cc1.ID = cc2.WantedID;
And to reject course completions that appeared later in the Excel table, simply replace MAX with MIN.
So using an integer primary key gives you some options.

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.

Replacing a specific char in a string

I have a table called Attendance and columns called attendanceStatus and CourseID. The attendanceStatus column is a text type because I wish to be able to change each 0 to a 1 at any given stage. The data is filled with 0's but I wish to change the last 0 in the string to a 1. The data contains 18 0's, so it would be the 18th character that I would need to change.
I feel like I have come close with this but I am willing to listen to changing it completely if I am not close.
UPDATE Attendance
SET attendanceStatus REPLACE = (attendanceStatus, '0', '1')
WHERE CourseID like '2%';
I realize that this code changes all of the 0's to 1's and I only wish to change the 18th 0.
You are storing attendance status using the wrong method. Although I can appreciate why you would store these in a string, it is really cumbersome. How are you going to answer: How many students attended for at least 10 days? How many students were around on day 6? How many students were absent for three days in a row?
The correct method is to have a separate row for each "day" (I'm not sure what the correct units are). It would be something like:
create table StudentAttendance (
StudentAttendanceId int not null primary key auto_increment,
StudentId int not null references Student(StudentId),
CourseId int not null references Courses(CourseId),
Date date,
status char(1),
constraint unq_scd unique (StudentId, CourseId, Date)
);
UPDATE Attendance
SET attendanceStatus = CONCAT( SUBSTRING(attendanceStatus,
1,
CHAR_LENGTH (attendanceStatus) - 1
),
'1' )
WHERE CourseID like '2%';

don't repeat entry row from two different table

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.

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.

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.