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 > ''.
Related
I am new to SQL.
I was wondering if there is a way to form a complex (I think) query of a certain form, regarding a single table - or a simple query for the same effect.
Let's say I have a table of voice actor candidates, with different attributes (columns) - name and characteristics.
Let's say I have two different actor evaluators (Stewie and Griffin), and all the candidates were evaluated by minimum one of them (one, or both). The evaluators evaluate the actors, and the table is built.
The rows in the table are per-evaluation, not per-person, meaning that some candidates have two separate rows, one from each evaluation.
The evaluator's name is also an attribute, a column.
Can I make a query that will choose all candidates that were evaluated by both evaluators? (and let's say show all these rows, an even number then)
(There is no attribute "evaluated by both" - that's the core)
I think it should find all rows with evaluator Stewie, then search the entire table for rows with the corresponding candidates' names, and get those with evaluator Griffin.
Summary
A table with people - names and characteristics. One or two rows per person. Each row was filled according to a different observer. There is an attribute "Is Nice". How to find all people that were observed by two observers, one marked "Yes" and one "No" under "Is Nice"?
Update
It will take me some time to check all the answers (as not enough experience yet), and I will update what worked for me.
Can I make a query that will choose all candidates that were evaluated
by both evaluators?
(and let's say show all these rows, an even number then)
There are multiple ways to do this. You can check the existence of other evaluator's evaluation, using EXISTS:
SELECT * FROM Candidate AS C1 WHERE EXISTS (SELECT * FROM Candidate AS C2 WHERE C1.id = C2.id AND C1.evaluator != C2.evaluator)
Or, you could join the table to itself: (The checks for evaluators should be changed as appropriate)
SELECT C1.candidateName FROM Candidate AS C1 JOIN Candidate AS C2 USING (id) WHERE C1.evaluator = Stewie AND C2.evaluator = Griffin
How to find all people that were observed by two observers, one marked
"Yes" and one "No" under "Is Nice"?
For this one, you add another condition to the queries above, that checks if one evaluation was "Yes" and the other one was "No".
You seem to want group by and having. SInce a person cannot have more than two rows, and there are only two distinct possible values for isnice (yes or no), we can phrase the query as:
select name
from people
group by name
having max(isnice) <> min(isnice)
This filter names that have (at least) two different values in isnice. Starting from the above assumptions, this is sufficient to ensure that that person was evaluated more than once, and that isnice has (at least) two different values.
So, I read the problem very carefully, and came up with my own solution.
Please verify the code below if this is what you were really asking for?
--Create Candidates Table
CREATE TABLE tbl_candidates
(
c_id INT PRIMARY KEY NOT NULL IDENTITY(1,1),
c_name VARCHAR(30),
)
--Create Evaluators Table
CREATE TABLE tbl_evaluators
(
e_id INT PRIMARY KEY NOT NULL IDENTITY(1,1),
e_name VARCHAR(30),
)
--Create Evaluations Table
CREATE TABLE tbl_evaluations
(
ee_id INT PRIMARY KEY NOT NULL IDENTITY(1,1),
ee_title VARCHAR(30) NOT NULL,
ee_remarks VARCHAR(30) NOT NULL,
ee_date date NOT NULL,
c_id INT FOREIGN KEY (c_id) REFERENCES tbl_candidates(c_id) NOT NULL,
e_id1 INT FOREIGN KEY (e_id1) REFERENCES tbl_evaluators(e_id) NOT NULL,
e_id2 INT FOREIGN KEY (e_id2) REFERENCES tbl_evaluators(e_id),
IsNice VARCHAR(4)
)
--Populate data & check to verify
INSERT INTO tbl_candidates (c_name) VALUES ('Sam') , ('Smith')
SELECT * FROM tbl_candidates
INSERT INTO tbl_evaluators (e_name) VALUES ('Stewie'),('Griffin')
SELECT * FROM tbl_evaluators
INSERT INTO tbl_evaluations
(ee_title,ee_remarks,ee_date,c_id,e_id1,e_id2,IsNice)
VALUES
('Some Title','Some Comment','2020-6-12',1,1,NULL,'No'),
('Some Title','Some Comment','2020-6-12',2,1,2,'Yes'),
('Some Title','Some Comment','2020-6-12',3,2,NULL,'No')
--finally comparing whether we have the matching data of our input vs tables combined data display
select * from tbl_evaluations
select ee_id,ee_title,c_name,ee_remarks,e1.e_name,e2.e_name,ee_date,IsNice from tbl_evaluations ee
left join tbl_candidates c on c.c_id = ee.c_id left join tbl_evaluators e1 on e1.e_id = ee.e_id1 left join tbl_evaluators e2 on e2.e_id = ee.e_id2
See the result proof :
This is surely not the best way to write it, but my first thought is
SELECT * FROM evaluations
WHERE PrName IN (
SELECT PrName
FROM evaluations
WHERE IsNice ='No')
AND PrName IN (
SELECT PrName
FROM evaluations
WHERE IsNice ='Yes')
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
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.
After my previous question (http://stackoverflow.com/questions/8217522/best-way-to-search-for-partial-words-in-large-mysql-dataset), I've chosen Sphinx as the search engine above my MySQL database.
I've done some small tests with it, and it looks great. However, i'm at a point right now, where I need some help / opinions.
I have a table articles (structure isn't important), a table properties (structure isn't important either), and a table with values of each property per article (this is what it's all about).
The table where these values are stored, has the following structure:
articleID UNSIGNED INT
propertyID UNSIGNED INT
value VARCHAR(255)
The primary key is a compound key of articleID and propertyID.
I want Sphinx to search through the value column. However, to create an index in Sphinx, I need a unique id. I don't have right here.
Also when searching, I want to be able to filter on the propertyID column (only search values for propertyID 2 for example, which I can do by defining it as attribute).
On the Sphinx forum, I found I could create a multi-value attribute, and set this as query for my Sphinx index:
SELECT articleID, value, GROUP_CONCAT(propertyID) FROM t1 GROUP BY articleID
articleID will be unique now, however, now I'm missing values. So I'm pretty sure this isn't the solution, right?
There are a few other options, like:
Add an extra column to the table, which is unique
Create a calculated unique value in the query (like articleID*100000+propertyID)
Are there any other options I could use, and what would you do?
In your suggestions
Add an extra column to the table, which is unique
This can not be done for an existing table with large number of records as adding a new field to a large table take some time and during that time the database will not be responsive.
Create a calculated unique value in the query (like articleID*100000+propertyID)
If you do this you have to find a way to get the articleID and propertyID from the calculated unique id.
Another alternative way is that you can create a new table having a key field for sphinx and another two fields to hold articleID and propertyID.
new_sphinx_table with following fields
id - UNSIGNED INT/ BIGINT
articleID - UNSIGNED INT
propertyID - UNSIGNED INT
Then you can write an indexing query like below
SELECT id, t1.articleID, t1.propertyID, value FROM t1 INNER JOIN new_sphinx_table nt ON t1.articleID = nt.articleID AND t1.propertyID = nt.propertyID;
This is a sample so you can modify it to fit to your requirements.
What sphinx return is matched new_sphinx_table.id values with other attributed columns. You can get result by using new_sphinx_table.id values and joining your t1 named table and new_sphinx_table
I'm building this tool for classifying data. Basically I will be regularly receiving rows of data in a flat-file that look like this:
a:b:c:d:e
a:b:c:d:e
a:b:c:d:e
a:b:c:d:e
And I have a list of categories to break these rows up into, for example:
Original Cat1 Cat2 Cat3 Cat4 Cat5
---------------------------------------
a:b:c:d:e a b c d e
As of right this second, there category names are known, as well as number of categories to break the data down by. But this might change over time (for instance, categories added/removed...total number of categories changed).
Okay so I'm not really looking for help on how to parse the rows or get data into a db or anything...I know how to do all that, and have the core script mostly written already, to handle parsing rows of values and separating into variable amount of categories.
Mostly I'm looking for advice on how to structure my database to store this stuff. So I've been thinking about it, and this is what I came up with:
Table: Generated
generated_id int - unique id for each row generated
generated_timestamp datetime - timestamp of when row was generated
last_updated datetime - timestamp of when row last updated
generated_method varchar(6) - method in which row was generated (manual or auto)
original_string varchar (255) - the original string
Table: Categories
category_id int - unique id for category
category_name varchar(20) - name of category
Table: Category_Values
category_map_id int - unique id for each value (not sure if I actually need this)
category_id int - id value to link to table Categories
generated_id int - id value to link to table Generated
category_value varchar (255) - value for the category
Basically the idea is when I parse a row, I will insert a new entry into table Generated, as well as X entries in table Category_Values, where X is however many categories there currently are. And the category names are stored in another table Categories.
What my script will immediately do is process rows of raw values and output the generated category values to a new file to be sent somewhere. But then I have this db I'm making to store the data generated so that I can make another script, where I can search for and list previously generated values, or update previously generated entries with new values or whatever.
Does this look like an okay database structure? Anything obvious I'm missing or potentially gimping myself on? For example, with this structure...well...I'm not a sql expert, but I think I should be able to do like
select * from Generated where original_string = '$string'
// id is put into $id
and then
select * from Category_Values where generated_id = '$id'
...and then I'll have my data to work with for search results or form to alter data...well I'm fairly certain I can even combine this into one query with a join or something but I'm not that great with sql so I don't know how to actually do that..but point is, I know I can do what I need from this db structure..but am I making this harder than it needs to be? Making some obvious noob mistake?
My suggestion:
Table: Generated
id unsigned int autoincrement primary key
generated_timestamp timestamp
last_updated timestamp default '0000-00-00' ON UPDATE CURRENT_TIMESTAMP
generated_method ENUM('manual','auto')
original_string varchar (255)
Table: Categories
id unsigned int autoincrement primary key
category_name varchar(20)
Table: Category_Values
id unsigned int autoincrement primary key
category_id int
generated_id int
category_value varchar (255) - value for the category
FOREIGN KEY `fk_cat`(category_id) REFERENCES category.id
FOREIGN KEY `fk_gen`(generated_id) REFERENCES generated.id
Links
Timestamps: http://dev.mysql.com/doc/refman/5.1/en/timestamp.html
Create table syntax: http://dev.mysql.com/doc/refman/5.1/en/create-table.html
Enums: http://dev.mysql.com/doc/refman/5.1/en/enum.html
I think this solution is perfect for what you want to do. The Categories list is now flexible so that you can add new categories or retire old ones (I would recommend thinking long and hard about it before agreeing to delete a category - would you orphan record or remove them too, etc.)
Basically, I'm saying you are right on target. The structure is simple but it will work well for you. Great job (and great job giving exactly the right amount of information in the question).