I'm going to keep it brief here for convenience's sake. I'm new to SQL coding, so please excuse me if I say something weird.
I did not manage to find a solid solution to it (at least one that I would truly understand), which is precisely why I'm posting here as a last resort at this point.
The table code:
create table companies (
company_id mediumint not null auto_increment,
Name varchar(40) not null,
Address varchar(40),
FoundingDate date,
primary key (company_id)
);
create table employees (
Employee_id mediumint not null auto_increment,
Name varchar (40),
Surname varchar(40),
primary key (Employee_id)
);
create table accounts (
Account_id mediumint not null auto_increment,
Account_number varchar(10) not null,
CompanyID int(10),
Date_of_creation date,
NET_value int(30),
VAT int(3),
Total_value int(40),
EmployeeID int(10) not null,
Description varchar(40),
primary key (Account_number)
);
Table values are random strings and numbers until I figure this out.
My issue is that I'm stuck at forming correct SQL queries, namely:
Query all accounts with their designated companies. I need it to show 'NULL' value if an account has no associated company.
Query that can list all accounts whose date is less than 2018-03-16 or those without a date.
Query that will print the description of the 'Accounts' table in one column and the number of characters in that description in a different column.
Query that lists all employees whose names end with '-gh' and that have names greater than 5 characters in length.
Query that will list the top total sum amount.
Query that will list all accounts that have '02' in them (i.e. 3/02/05).
If you can answer at least one of these queries and if you can explain how you got to the solution in a simplistic manner, well... I'm afraid I have nothing to offer but honest gratitude! ^^'
Welcome to the community, but as Jerry commented, you should really try to show SOMETHING that you have tried just to show what you THINK is needed. Also, don't just add comments to respond, but edit your original post with additional details / data as people ask questions.
To try and advance you forward though, I will point out two specific links that should help you out. The first one is a link for the basics on querying explaining the
select [fields] from [what table] join [other tables] where [what is your criteria] -- etc. Some Basics on querying
The next give some very good clarification on JOIN conditions of (INNER) JOIN -- which means required record match in BOTH tables being joined, and FULL OUTER JOINS, LEFT JOINs, etc.
After reviewing those, if you STILL have questions, please edit your original question, post some samples of what you THINK is working and let us know (or comment back to a specific answer), and we in the forum can follow-up with you.
HINT, your first query wanting NULL you should get from the visual link via LEFT JOIN.
A visual representation and samples on querying
Related
I have two doubts:
I have a table as follows:
AUTHOR
(
authorID int NOT NULL,
authName varchar(255) NOT NULL,
authSurname varchar(255),
authPlaceOfBirth varchar(255),
authDOB date(),
authDoD varchar(255),
PRIMARY KEY (authorID)
)
Now, I want to find the authors who have died. That is, if the value of DoD exists in the table, then they have died. How to do this? That is, a particular value in a column exists?
Something like this:
SELECT authName
FROM AUTHOR
WHERE authDoD is not NULL?
Second, I have two tables as follows:
TABLE inventory_genre
{
genreID int NOT NULL,
inventoryID int NOT NULL,
PRIMARY KEY (genreID,inventoryID)
}
TABLE INVENTORY
{
inventoryID int NOT NULL,
title varchar(255),
wholesale int,
markup int,
qtyinStock int,
Discount int,
PRIMARY KEY (inventoryID)
}
I want to list all the genres that have no associated titles in the inventory. I know I have to subtract but I am not able to come up with it exactly. Please guide me in the right direction!
Not sure I understand the criteria you are describing in the first question, but either
select * from author where authDOB is not null;
or
select * from author where authDOB = 'some value that I dont know';
For the second one, you could use exists or in with a nested select:
select * from genre where id not in (select genreId from inventory_genre);
Part 1
Think about it logically:
you're looking for people who are referenced by what?
By their death.
How do you know they're dead?
Because a certain field in the table has been filled in.
Can you quantify this?
Yes, the value of their death exists.
So, yon can construct an SQL search that looks in the table of Authors for rows (people) where the column (authDoD) value is not nothing/null.
As a note for a perfect world you should have IS NULL set in the column authDoD so that if no value is set the column row value is NULL and easier to handle in queries.
SQL (assuming column can be empty but not Null):
SELECT * FROM authors WHERE authDoD > ''
SQL (assuming column can only be null unless dead):
SELECT * FROM authors WHERE authDoD IS NOT NULL
Part 2
You want to return a negative search, a search that turns up no results, so find each genre which does not feature in any inventory table row.
While I'm about to write a longer answer for this, the answer just posted by Tobb does exactly what you need.
Also note that you should ideally have an INDEX on your ID columns to make traversing them smoother and faster.
For the first part of your question, you could use
SELECT * FROM AUTHOR WHERE authDoD IS NOT NULL;
This would SELECT the deceased people
Your first problem is solved, if you check for authorDoD > ''. It will evaluate to false if there's NULL or the empty string ''.
To solve your second problem you could just JOIN your tables, since the inventoryID isn't allowed to be NULL.
JOIN INVENTORY i ON (inventory_genre.inventoryID = i.inventoryID)
After that you can check the existence of an title like above with title > ''.
This is my first question in stackoverflow and I am delighted to be part of this community because it has helped me many times.
I'm not an expert in SQL and MySQL but I'm working in a project that needs large tables (million rows). I have a problem when doing a join and I don't understand why it takes so long. Thanks in advance:)
Here are the tables:
CREATE TABLE IF NOT EXISTS tabla_maestra(
id int UNIQUE,
codigo_alta char(1),
nombre varchar(100),
empresa_apellido1 varchar(150),
apellido2 varchar(50),
tipo_via varchar(20),
nombre_via varchar(100),
numero_via varchar(50),
codigo_via char(5),
codigo_postal char(5),
nombre_poblacion varchar(100),
codigo_ine char(11),
nombre_provincia varchar(50),
telefono varchar(250) UNIQUE,
actividad varchar(100),
estado char(1),
codigo_operadora char(3)
);
CREATE TABLE IF NOT EXISTS tabla_actividades_empresas(
empresa_apellido1 varchar(150),
actividad varchar(100)
);
Here is the query I want to do:
UPDATE tabla_maestra tm
INNER JOIN tabla_actividades_empresas tae
ON (tm.nombre!='' AND tae.empresa_apellido1=tm.empresa_apellido1)
SET tm.actividad=tae.actividad;
This query takes too long, and before executing it I was trying to test how long takes this simplier query:
SELECT COUNT(*) FROM tabla_maestra tm
INNER JOIN tabla_actividades_empresas tae
ON (tm.nombre!='' AND tae.empresa_apellido1=tm.empresa_apellido1);
It is still taking too long, and I don't understand why. Here are the indexes I use:
CREATE INDEX cruce_nombre
USING HASH
ON tabla_maestra (nombre);
CREATE INDEX cruce_empresa_apellido1
USING HASH
ON tabla_maestra (empresa_apellido1);
CREATE INDEX index_actividades_empresas
USING HASH
ON tabla_actividades_empresas(empresa_apellido1);
If I use the EXPLAIN statement, these are the results:
http://oi59.tinypic.com/2zedoy0.jpg
I would be so grateful to receive any answer that could help me. Thanks a lot,
Dani.
A join involving half a million rows -- as your query plan shows -- is bound to take some time. The count(*) query is quicker because it doesn't need to read the tabla_maestra table itself, but it still needs to scan all the rows of index cruce_empresa_apellido1.
It might help some if you made index index_actividades_empresas a unique index (supposing that that's indeed appropriate) or if instead you drop that index and make column empresa_apellido1 a primary key of table tabla_actividades_empresas.
If even that does not give you sufficient performance, then the only other thing I see to do is to give table tabla_actividades_empresas a synthetic primary key of integer type, and to change the corresponding column of tabla_maestra to match. That should help because comparing an integer to an integer is faster than comparing a string to a string, even when you can filter out (most) mismatches via a hash.
I agree with the other ones (see John Bollinger i.e.) about the lack of Primary Keys on it. It's highly adiviced for IDs (I noticed you worry about it be repeated, but PK smoothly treats it too - I meant MySQL's AUTOINCREMENT).
Why do you use the tabla_actividades_empresas.empresa_apellido1 instead of look for tabla_maestra's ID to be referenced in?
If so, you could define Foreign Key to it: tabla_actividades_empresas.maestra_id i.e.
Because it gets better if you associate tables with non-strings types.
You also can subquery the tables before the JOIN action between them. It's an example:
UPDATE (SELECT * FROM tabla_maestra WHERE nombre != '') AS tm
INNER JOIN tabla_actividades_empresas AS tae
ON tae.empresa_apellido1 = tm.empresa_apellido1
SET tm.actividad = tae.actividad;
I have not tested it. But it seems to be a nice behavior to follow since then.
Oh... everytime do you need to update all the data rows? Unless, you can update only the forgotten ones. You can apply the UPDATE by INNER JOIN after one LEFT JOIN to determine the needed ones to be updated. Does it have sense? I'm not any expert, but it can be useful to think about.
EDIT
You may test some subquery too:
UPDATE tabla_maestra AS main, tabla_actividades_empresas AS aggr
SET main.actividad = aggr.actividad
WHERE main.empresa_apellido1 = aggr.empresa_apellido1
AND main.nombre <> ''
Don't forget to try of adjusting the relationship.
Thank you so much for your answers.
The fact is that table 'tabla_maestra' is a table that contain information about enterprises, but does't contain the values for the 'actividad' field (activity of the enterprise). Moreover, the 'id' field is still empty (I will it in a future. It is difficult to explain why, but it has to be done this way).
I need to add the activity of each enterprise joining with an auxiliar table 'tabla_actividades_empresas', which contain the activity for each enterprise name. And I only have to do it one time, no more. Then I will be able to drop the table 'tabla_actividades_empresas' because I won't need it.
And the only way to join them is by the field 'empresa_apellido1', it is to say, the name of the enterprise.
I have made the field 'tabla_actividades_empresas.empresa_apellido1' unique, but it doesn't improve the performance.
And it doesn't have sense to define a foreign key on 'tabla_actividades_empresas' because the field 'empresa_apellido1' is UNIQUE only for the 'tabla_actividades_empresas', not for the 'tabla_maestra' (in this table, an enterprise name can appear many times because enterprises can have different offices in different places). It is to say, 'tabla_actividades_empresas' doesn't contain repeated enterprises, but 'tabla_maestra' has repeated name enterprises.
By the way, what do you mean by "adjusting the relationship"? I have tried your subqueries with the explain statement, and it doesn't use the indexes correctly, the performance is worse.
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.
My questions comes first, then I'll describe the whole situation and current solution:
Questions.
1. Why could mySQL make enormously lots of continous read|write (300-1000 megaBytes) disk operations?
2. Is DB structure optimal (need advice otherwise)?
3. Do UniqueKey could slow down DB?
4. What could be better solution for the situation?
5. At the end vServer is getting down and I got mail with ~'ETIMEDOUT: Connection timed out - connect (2)'; So maybe issue is not in DB structure but it is some misconfiguration?
Situation.
Users on the end devices are playing and when gameover comes they are storing game records in central DB. Users could see highscores table sorted by hignscore.
I cant say that there are a lot of users. Lets assume that 1 user per 1 min.
Solution.
LAMP.
Since there are several similar games that users are playing there are several similar tables+views pairs in DB. (~25 Tables+25 Views total). Most of tables contain ~30 000 records. 3 of them contain up to 150 000 records.
In order to store users uniquely: 1user-1record I made a unique key UNIQUE INDEX userid (userid, gamename, gametype, recordvalue).
Since user should see sorted values (highscores) I made a view for a table that shows what is needed. So the external php script is working with view rather then with table.
CREATE TABLE supergameN (
id INT(11) NOT NULL AUTO_INCREMENT,
userid VARCHAR(255) NOT NULL,
username VARCHAR(50) NOT NULL,
gamename VARCHAR(100) NOT NULL,
gametype VARCHAR(100) NOT NULL,
description VARCHAR(100) NULL DEFAULT 'empty',
recordvalue INT(11) NOT NULL,
PRIMARY KEY (id),
UNIQUE INDEX userid (userid, gamename, gametype, recordvalue)
)
CREATE VIEW supergameN_view AS
SELECT
id,
userid,
username,
gamename,
gametype,
description,
recordvalue
FROM supergameN
ORDER BY gametype, recordvalue DESC
Thanks in advance. Alex.
Maybe not the solution but something I noticed:
Leave out the recordvalue from the unique key, since otherwise you would allow several records to exist for each userid-gamename-gametype combination, as long asd they have different recordvalues!
By using
UNIQUE INDEX userid (userid, gamename, gametype)
You ensure that per game and user you only ever store one result.
And, some further remarks/questions:
Do you really need two columns to identify the game?
What is kept in description: is it user or game related?
Maybe you could normalize a bit by having just a gameid column in your main table and (assuming that description refers to the game) a separate table games with columns gameid, gamename,gametypeand description. And then, of course, there would be no need to keep id anymore, instead you would have the combination of (userid,gameid) as your primary key.
What's the best way to query one-to-many in MySQL? This is a simplified version of the database I am working on (if anything doesn't look right tell me):
CREATE TABLE Tenant(
tenant_id int NOT NULL,
first_name varchar(20),
last_name varchar(20),
PRIMARY KEY (tenant_id)
);
CREATE TABLE Rent(
tenant_id int NOT NULL,
month enum('JAN', 'FEB', ...),
date_paid date NOT NULL,
amount_paid int NOT NULL,
FOREIGN KEY (tenant_id) REFERENCES Tenant(tenant_id)
);
(The reason that there is month and date_paid in the Rent table is because the tenant does not necessarily pay the rent all at once). What I want the tenant's name to appear once which would just be a Left Join, but I want all the amount paid in a particular month listed as columns for each tenant, I am not sure how to go about that. I am not really sure how to do that since your are dealing with an unknown amount of columns, haven't touched that yet in MySQL. Or is there a better strategy? Also, how would I go about creating my own variable like MONTH-YEAR (I don't think that exists as a native variable in MySQL). Thank you!
Edit:
Just to simplify it further I am using this format:
create table rent(
tenant_id int not null,
year year,
amount_paid int,
foreign key (tenant_id) references tenant(tenant_id)
);
If I understand what duffymo said below I should use group by (I know I am misunderstanding somewhere because it only shows the first example for each year):
SELECT Tenant.first_name, Rent.year, Rent.amount_paid
FROM Tenant
LEFT JOIN Rent
ON Tenant.tenant_id = Rent.tenant_id
GROUP BY year;
This is what I want the query to look like, the number under each year is the amount paid (I actually just realized it's a little bit more complex than what I how explained):
first_name 2009 2008 2007
John 500 500 NULL
Ann 1000 NULL NULL
Bob NULL 700 700
If you have MONTH and YEAR columns, you can do a GROUP BY to select amount paid broken out as you'd wish. If you have a PAID_DATE column, one way to do this would be to have a BEFORE INSERT trigger that runs when the PAID_DATE is set. That way users don't have to enter values, and data integrity can be guaranteed.