MySQL: referring to a composite key - mysql

I have 3 columns: name, age, address.
I want name and age to be a composite key to refer to an address.
Create table usertable (
name varchar(100) not null,
age int not null,
address varchar(100) not null,
constraint addresskey PRIMARY KEY(name,age)
);
This works:
select * from usertable where (name,age)=('somename',someage);
But i would like to do something like:
select * from usertable where addresskey=('somename',someage);
I get an error when I do this.

In that way you want to say that you put the primary key for the addresskey.
1) It's not a good idea to put name and age as primary key because there should be some duplicates.
2) You get an error because the query is wrong because you don't have a field named addresskey and in the query you compare a varchar with 2 fields.
So if you want to do that you can add a field addresskey as an auto_increment field (but pay attention to manage the same address, decide how it could works) and then you can select using addresskey value.

Related

how to avoid blank space while using char field in sql

I have two tables one is a customer table and the second is sales table.
I need to create a query to display customer name, customer_id and number of Gadgets bought (write two queries using different syntaxes of JOIN). Example : “John Barry - 111 bought 5 gadgets”.
CUSTOMERS_JS
create table CUSTOMERS_JS (
CUSTID smallint not null,
CUSTNAME char(50) not null,
primary key(CUSTID)
);
STORE_SALES_JS
create table STORE_SALES_JS (
SALEID smallint not null,
SALETS datetime not null,
GADGETID smallint not null,
EMPID smallint not null,
CUSTID smallint not null,
primary key(SALEID),
foreign key(GADGETID) references ELEC_items_JS(GADGETID),
foreign key(EMPID) references Store_EMPS_JS(EMPID),
foreign key(CUSTID) references CUSTOMERS_JS(CUSTID)
);
I did this query
select concat(CUSTNAME,' - ',STORE_SALES_JS.CUSTID,' bought ',count(STORE_SALES_JS.GADGETID),' gadgets') as result
from CUSTOMERS_JS,STORE_SALES_JS
where STORE_SALES_JS.CUSTID = CUSTOMERS_JS.CUSTID
group by STORE_SALES_JS.CUSTID,CUSTNAME
order by STORE_SALES_JS.CUSTID
but there is too much space between the name and the '-'. I tried to change the name field to varchar and it worked as it supposed to work but I need it to work with char(50) as well.
Thanks to scaisEdge help I managed to fix this issue while using rtrim function
select concat(rtrim(CUSTNAME),' - ',STORE_SALES_JS.CUSTID,' bought ',count(STORE_SALES_JS.GADGETID),' gadgets') as result
from CUSTOMERS_JS,STORE_SALES_JS
where STORE_SALES_JS.CUSTID = CUSTOMERS_JS.CUSTID
group by STORE_SALES_JS.CUSTID,CUSTNAME
order by STORE_SALES_JS.CUSTID
if you must use char and not varchar but need a trimmed result in your select you could trim ( or rtrim or ltrim) your custname for remove the spaces
select concat(rtrim(CUSTNAME),' - '
,STORE_SALES_JS.CUSTID,' bought '
,count(STORE_SALES_JS.GADGETID),' gadgets') as result
from CUSTOMERS_JS,STORE_SALES_JS
where STORE_SALES_JS.CUSTID = CUSTOMERS_JS.CUSTID
group by STORE_SALES_JS.CUSTID,CUSTNAME
order by STORE_SALES_JS.CUSTID

modeling issue with field with 4 values (1 or more)

lets say I have an account object in my application, which currently represented as:
CREATE TABLE Account (
accountId int NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
PRIMARY KEY (accountId)
);
Now, Account object need to also have Solution field...and Status have 4 different possible values:
Solution1, Solution2, Solution3, Solution4
What would be the right way to represent it in the database?
Account can have few statuses, and status can have few accounts...
So at first I thought create in the db table of Solutions and than have another table to hold the relationship, but its seems too complicated for a field that have only 4 possible values...
Create a junction table to represent the relationships between accounts and solutions:
CREATE TABLE account_solution (
accountId int NOT NULL,
solutionId int NOT NULL
PRIMARY KEY (accountId, solutionId)
)
For your solution table, since there are only 4 values, you might be able to take advantage of MySQL's enum type, e.g.
CREATE TABLE solution
solutionId int NOT NULL PRIMARY KEY,
status ENUM('Solution1', 'Solution2', 'Solution3', 'Solution4')
);
You can use set Mysql SET type
CREATE TABLE Account (
accountId int NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
status set('Solution1','Solution2','Solution3','Solution4') NOT NULL,
PRIMARY KEY (accountId)
);
And if you want to select a specific status
SELECT *
FROM `Account`
WHERE FIND_IN_SET( 'Solution2', `status` ) >0

MySQL - add data into 2 tables and 1 has foreign key

I'm a totally MySQL newcomer. Sr if my question is quite obvious. I got 2 tables
CREATE TABLE tbl_addresses(
PK_ADDRESS_ID int NOT NULL AUTO_INCREMENT,
house_number int NOT NULL,
street varchar(35),
district varchar(35),
city varchar(35),
postcode varchar(8),
PRIMARY KEY (PK_ADDRESS_ID)
);
CREATE TABLE tbl_people(
PK_PERSON_ID int NOT NULL AUTO_INCREMENT,
title varchar(6) NOT NULL, # Master / Mister therefor 6 is max
forename varchar(35) NOT NULL,
surname varchar(35) NOT NULL,
date_of_birth DATE NOT NULL,
contact_number varchar(12) NOT NULL,
FK_ADDRESS_ID int NOT NULL,
PRIMARY KEY (PK_PERSON_ID),
FOREIGN KEY (FK_ADDRESS_ID) REFERENCES tbl_addresses (PK_ADDRESS_ID)
);
and I'm trying to import data into these tables from Java using below syntaxes
INSERT INTO tbl_addresses (house_number,street,district,city,postcode) VALUES ('1','abc','','abc','abc');
INSERT INTO tbl_people (title,forename,surname,date_of_birth,contact_number) VALUES ('Mr','Tri ','Nguyen','1991-1-1','0123456789');
I got an error Field 'FK_ADDRESS_ID'doesn't have a default value and data actually goes into tbl_addresses but not tbl_people. Am I missing anything? Thanks in advance!
This error is being caused by that you labelled the FK_ADDRESS_ID field in the tbl_people table as NOT NULL, yet you are trying to do an INSERT without specifying a value for this column.
So something like this would work without error:
INSERT INTO tbl_people (title, forename, surname, date_of_birth,
contact_number, FK_ADDRESS_ID)
VALUES ('Mr', 'Tri', 'Nguyen', '1991-1-1', '0123456789', 1);
You could also specify a default value for FK_ADDRESS_ID (the error message you got alluded to this). Here is how you could adda default value:
ALTER TABLE tbl_people MODIFY COLUMN FK_ADDRESS_ID int NOT NULL DEFAULT 1
But because FK_ADDRESS_ID is a key into another table, the value should really be based on the primary key in tbl_addresses.
The fact that you are using a foreign key isn't the reason that you are getting this error. Let's take a look at your column definition.
FK_ADDRESS_ID int NOT NULL,
This is not null but does not a default. Now a look at your insert statement
INSERT INTO tbl_people (title,forename,surname,date_of_birth,contact_number)
FK_ADDRESS_ID isn't in your column list but it cannot be null and doesn't have a default so what can mysql do? Produce an error of course.
The best bet is to define that column as nullable.
Let's revisit the foreign key constraint.
FOREIGN KEY (FK_ADDRESS_ID) REFERENCES tbl_addresses (PK_ADDRESS_ID)
What this really says is that if you asign a value to FK_ADDRESS_ID that value should be present in PK_ADDRESS_ID column in tbl_address
as a side note, it's customary to use lower case for table/column names.

How do I get a row of the same type from one table or another table along with the information about from which table it was

Let's say I have tables:
create table people (
human_id bigint auto_increment primary key,
birthday datetime );
create table students (
id bigint auto_increment primary key,
human_id bigint unique key not null,
group_id bigint not null );
create table teachers (
id bigint auto_increment primary key,
human_id bigint unique key not null,
academic_degree varchar(20) );
create table library_access (
access_id bigint auto_increment primary key,
human_id bigint not null,
accessed_on datetime );
Now I want to display information about a library access, along with the information whether it was a student or a teacher (and then the id corresponding to the table) (let's say I want something like SELECT access_id,id,true_if_student_false_if_teacher FROM library_access), in an idiomatic way.
How do I form the query (in case such database was already deployed) and what are better and more idiomatic ways to solve that problem (in case it wasn't deployed so far).
MariaDB 5.5, database accessed by Go and nothing else.
Thanks in advance.
You said you need to know which table the data comes from. You can use union all for this:
select la.access_id, s.id, 'Students' as source_table
from library_access la
join students s on la.human_id = s.human_id
union all
select la.access_id, t.id, 'Teachers' as source_table
from library_access la
join teachers t on la.human_id = t.human_id
Without looking at your tables or any idea as to what you want returned in the select statement:
SELECT *
FROM people a,
students b,
teachers c,
library_access d
WHERE a.human_id = b.human_id
AND a.human_id = c.human_id
AND a.human_id = d.human_id

correct way to place data in table OneToONe

I am confused about the correct/most efficient way to place data in my dababase table when there is a OneToOne relationship.
For example, I have a users table.
I now wish for each user to be able to state his current country location.
i then want to be able to search the datatable for users by current location.
The way that I have done this is to create 3 separate tables. i.e
table one - users : just contains the user information:
CREATE TABLE users(
id MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT,
firstName VARCHAR(30) NOT NULL,
lastName VARCHAR(40) NOT NULL,
);
Table two country list: a list of countries and respective Ids for each country
PHP Code:
CREATE TABLE countrylist(
country_id MEDIUMINT UNSIGNED NOT NULL,
country VARCHAR(60) NOT NULL,
INDEX country_id ( country_id, country ),
INDEX countrylist (country, country_id ),
UNIQUE KEY (country)
);
Table 3; contains the userId and the countryId he lives in:
PHP Code:
CREATE TABLE user_countrylocation(
country_id VARCHAR(60) NOT NULL,
id MEDIUMINT UNSIGNED NOT NULL,
INDEX country_id (country_id, id ),
INDEX user_id (id, country_id )
);
Alternatively, should I place the countryId in the users table and completely get rid of the user_countrylocation. i.e in each user column, I will place a country_id for the country he lives in.
The problem is that I have over 20 similar tables as above that give details on users; i.e languages spoken, age-group, nationality etc.
My concerns is that if I place this unique information in each users column in the user table, then what would be the most efficient way to search the database: that is why I opted for the style above.
So, I really request for some advice on the most efficient/correct way to plan the database.
If you are going to have a huge data then you should keep the same approach and use the following method to keep the one to one constraint satisfied
if you don't have a huge data then you should keep the look up tables like country and use the reference for user in a column. but then you may need to allow them nulls that is make such optional information columns nullable.
The most efficient and exactly correct way is to first delete the data from the third table "user_countrylocation" for the user to be updated. Then insert the new location for the user. don't forget to use transaction.
your table 3 should have
country_id MEDIUMINT UNSIGNED NOT NULL,
instead of
country_id VARCHAR(60) NOT NULL,
and also change tyhe column name from id to user_id in all tables.
if you are using a stored procedure it would be like
create procedure sp_UpdateUserCurrentCountry (
#userID MEDIUMINT UNSIGNED,
#CountryID MEDIUMINT UNSIGNED)
begin
as
delete from user_countrylocation
where user_id = #userID
insert into user_countrylocation
(
country_id,
user_id
)
values
(
#CountryID,
#userID
)
END
One to One relations are usually mapped via Foreign Keys linking the two tables together. A third mapping table is only required for Many to Many relationships. So, you should ideally have a Foreign Key Country_ID in your Users table.
Your SELECT query would then look like
SELECT * FROM Users
WHERE Country_ID = (
SELECT Country_ID FROM Countries
WHERE Country_Name = 'USA'
);