Trouble understanding how to create a Join & Require query - mysql

So, I guess I should explain what I mean by a Join & Require Query as this probably isn't the correct term. For this question I set up a very simple subset of tables that would be out of a wireframe for a video game. I apologise in advance, SQLFiddle isn't working right now.
CREATE TABLE reqs (
crafted_id INT, item_id INT );
CREATE TABLE items (
id INT, name VARCHAR(30) );
CREATE TABLE crafted (
id INT, name VARCHAR(30) );
With these tables, I also created some sample data. I didn't use auto_increment in these tables so you could have a better visual.
INSERT INTO items (id, name) VALUES (1, 'Herbs');
INSERT INTO items (id, name) VALUES (2, 'Health Potion');
INSERT INTO items (id, name) VALUES (3, 'Leather');
INSERT INTO items (id, name) VALUES (4, 'Sticks');
INSERT INTO crafted (id, name) VALUES (101, 'Cured Leather');
INSERT INTO crafted (id, name) VALUES (102, 'Tea');
INSERT INTO reqs (crafted_id, item_id) VALUES (101, 1);
INSERT INTO reqs (crafted_id, item_id) VALUES (101, 3);
INSERT INTO reqs (crafted_id, item_id) VALUES (102, 1);
In this example I have setup a very minimalistic example of a crafting system in a game, where a crafted item requires other items.
I need to create a query in which I can pull all of the available values from the crafted table based on the items that I have. For example, based on the data above, I would do the following:
requestCraftableItems(itemArray) {
// Execute query based on array here
};
requestCraftableItems([1, 2, 3])
This should execute a query stating that the user has items 1, 3, & 4 and try to find a crafted entry where all of the reqs.item_id for reqs.crafted_id are met in the item array. In this example nothing should be returned, because the crafted_id for cured leather requires items 1 & 3 and the crafted_id for tea requires item 1
So if the user executed the following:
requestCraftableItems([1, 3, 4]);
It should return the crafted entry for Cured Leather AND Tea as the user supplied 1 & 3 to the query.
This is not my originally use case and is just an example to get the point of what I'm trying to do across on a very simple scale.
EDIT: To clairfy, if the value (1) is passed to the query, Cured Leather should not appear in the results, as Cured Leather requires BOTH 1 and 3.

I may have misunderstood what you are looking for, but a simple join should return the result you want:
SELECT crafted.name
FROM items
JOIN reqs
ON reqs.item_id = items.id
JOIN crafted
ON crafted.id = reqs.crafted_id
WHERE items.id in (1,3,4)
GROUP BY crafted.id
This would return the results in your examples.
Not tested, may contain typos

Related

Show count of seasons from table "episodes" can't format the query

Hello guys well I have a site where have anime episodes in a table episodes that table stores the normal info of an episose and a column season and that is the question: I wanna format a query to show how much seasons exist searching in the episodes posted where id = $serieid and season = $season >> but my brain is blocked really I don't know a lot MySQL:
SELECT Count(*)[??Seasons] FROM episodes WHERE id = $serie_id;
I really get confused I have little experience in MySQL.
Any help is appreciated.
I created a new table named "tAnime" in order to give you a full working code. Assuming that you have all the chapters for each season stored in the table, if you want to know how many seasons there are you just have to check for the maximum value in the column "season".
/* Database table creation */
CREATE TABLE tAnime(id integer PRIMARY KEY, title text, chapter integer, season integer);
/* Inserting some values */
INSERT INTO tAnime values(1, 'My Name is Konohamaru!', 2, 1);
INSERT INTO tAnime values(2, 'The Oath of Pain', 8, 1);
INSERT INTO tAnime values(3, 'The Forest of Chakra', 10, 1);
INSERT INTO tAnime values(4, 'Clone vs. Clone: Mine are Better than Yours!', 36, 2);
INSERT INTO tAnime values(5, 'A Failure Stands Tall!', 47, 2);
/* Selecting the number of seasons the anime has */
SELECT MAX(season) AS numberOfSeasons FROM tAnime;
That will do.

MySQL Insert results of select

I have a many to many relationship and am trying to insert a new relationship. At the point I'm doing the insert I don't know the id so would need to look it up. My table structure looks something like this:
**person**
id
name
**film**
id
title
**person_film**
personId
filmId
Given a person's id and a list of film titles (but not their ids) I'm only able to insert these relationships into the person_film table in two steps.
SELECT id FROM film WHERE title="film1" OR title="film2";
Then the results of that can be used in an insert:
INSERT INTO person_film (personId, filmId) VALUES (5, 5),(5, 7);
Is there a way of doing this in a single SQL statement?
You can do it with a subquery:
INSERT INTO person_film (personId, filmId)
SELECT 5, id FROM film
WHERE title IN("film1","film2");
Here the 5 is the personId value and the filmId will be retrieved from the film table.
Use numeric literals with aliases inside a SELECT statement. No () are necessary around the SELECT component.
INSERT INTO person_film (personId, filmId)
SELECT
/* Literal number values with column aliases */
1 AS fpersonId,
2 AS filmId,
FROM film
WHERE title="film1" OR title="film2";
Note that in context of an INSERT INTO...SELECT, the aliases are not actually necessary and you can just SELECT 1, 2 but in a normal SELECT you'll need the aliases to access the columns returned.

How avoid joining multiple times to the same table to get results back in single rows?

I have a schema that requires joining to the same table multiple times to get more information on the data pointed to by the columns. Below is an example schema that shows this situation:
SQL Fiddle: http://sqlfiddle.com/#!9/7a4019/1
CREATE TABLE STATE
(
employee INT NOT NULL,
boss INT,
manager INT,
rep INT
);
CREATE TABLE EMPLOYEE
(
id INT NOT NULL,
name VARCHAR(255) NOT NULL
);
INSERT INTO EMPLOYEE (id, name) VALUES (1, "Joe");
INSERT INTO EMPLOYEE (id, name) VALUES (2, "John");
INSERT INTO EMPLOYEE (id, name) VALUES (3, "Jack");
INSERT INTO EMPLOYEE (id, name) VALUES (4, "Jeff");
INSERT INTO EMPLOYEE (id, name) VALUES (5, "Jason");
INSERT INTO STATE (employee, boss, manager, rep) VALUES (1, 2, 3, 4);
INSERT INTO STATE (employee, boss, manager, rep) VALUES (2, 3, 3, 4);
INSERT INTO STATE (employee, boss, manager, rep) VALUES (3, NULL, NULL, 4);
INSERT INTO STATE (employee, boss, manager, rep) VALUES (4, 3, 3, NULL);
INSERT INTO STATE (employee, boss, manager, rep) VALUES (5, 2, 3, 4);
Currently, the only way i know to get this information in single rows for each employee, is left joining multiple times like this:
SELECT employee, b.name AS boss, m.name AS manager, r.name AS rep
FROM STATE
LEFT JOIN EMPLOYEE b ON b.employee = STATE.boss
LEFT JOIN EMPLOYEE m ON m.employee = STATE.manager
LEFT JOIN EMPLOYEE r ON r.employee = STATE.rep
Is there a way to do it without joins and without subqueries?
You asked:
Is there a way to do it without joins and without subqueries?
Not really. You are using the JOIN operations precisely as they're intended to be used -- each JOIN reflects a specific relationship between rows of a table.
You can avoid doing multiple joins by using aggregate functions, which I recently found useful after hitting the limit (61) of the number of joins that can be done in a query in MySQL/MariaDB.
SELECT s.employee,
GROUP_CONCAT(if(e.id=s.boss, name, NULL)) as boss,
GROUP_CONCAT(if(e.id=s.manager, name, NULL)) as manager,
GROUP_CONCAT(if(e.id=s.rep, name, NULL)) as rep,
FROM STATE s, EMPLOYEE e
GROUP BY s.employee
The above example uses MySQL's GROUP_CONCAT function. It appears not to be an ANSI standard. Other relational databases may have similar functions. A cursory web search turned up a page that discussed aggregate functions for various relational databases: http://www.postgresonline.com/journal/archives/191-String-Aggregation-in-PostgreSQL,-SQL-Server,-and-MySQL.html

MySQL: show strings in result that were not found

I have a MySQL db table with a column containing strings. And I have a list of strings. Some of the strings from the list can be found in my table, others can't. See my table TableName:
<TableName>
IntegerColumn, StringColumn
1, one
2, two
3, three
4, four
If I execute the query
SELECT * FROM TableName WHERE StringColumn NOT IN ('three', 'four', 'five', 'six');
I get a result of two rows, which contain nothing but NULL.
How can I see for which of the strings there was no match? Because I want to add them to the db table
Thx in advance
Using the following sample
CREATE TABLE sample_table
(
id int auto_increment primary key,
details varchar(30)
);
INSERT INTO sample_table
(id, details)
VALUES
(1, 'One'),
(2, 'Two'),
(3, 'Three'),
(4, 'Four'),
(5, 'Five');
I ran the query
SELECT * FROM sample_table
WHERE details NOT IN ('two', 'three', 'nine');
which gave the correct output of:
1 One
4 Four
5 Five
If you've got NULL returned then there is something you're not explaining in your question. Can you provide schema information or even a SQL Fiddle and I'm sure you'll get a much better answer.
I think what you want is, 'three', 'four', 'five', 'six' if any of this string is not present in the database you want to identify that.
Using query I think it will be tough. You can just use below query to get the available strings and the counts. Then, if you are using a programming language you can identify which string are not present in the result and then proceed further.
SELECT StringColumn, count(*) FROM TableName group by StringColumn
Not sure if this is what you are looking for.
This should not go this way. Check the following demo to ensure that your code is correct. Now what really matters is the set of data present in the table.
DEMO
Here is the DDL:
create table tab1 (IntegerColumn int(2), StringColumn varchar(20));
insert into tab1 values(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four');

MySQL string search between commas

My db is built as follows:
value1,value2,value3 | 1
value4,value5,val"u6 | 2
value 5, value 6, value 8 |3
(Two columns, one with a key separated by commas and the other just a normal var-char)
I'm looking for the most reliable way to find a query within the quotes and I'm getting kinda lost here.
I'm using the word boundaries for that:
SELECT * FROM ABC WHERE content REGEXP '[[:<:]]value 5[[:>:]]'
The problem is when I'm doing this query:
SELECT * FROM ABC WHERE content REGEXP '[[:<:]]5[[:>:]]'
It will also return the value, which is not what I'm looking for. Another problem is that the word boundaries refer to quotes as a word boundary
How can I solve this and create a simple query that will only fetch the exact full query between the quotes?
BTW
I don't have an option to change the DB structure...
As #MarcB commented, you really should try to normalise your schema:
CREATE TABLE ABC_values (
id INT,
content VARCHAR(10),
FOREIGN KEY (id) REFERENCES ABC (id)
);
INSERT INTO ABC_values
(id, content)
VALUES
(1, 'value1'), (1, 'value2'), (1, 'value3'),
(2, 'value4'), (2, 'value5'), (2, 'val"u6'),
(3, 'value 5'), (3, 'value 6'), (3, 'value 8')
;
ALTER TABLE ABC DROP content;
Then, as required, you can perform a SQL join between your tables and group the results:
SELECT id, GROUP_CONCAT(ABC_values.content) AS content
FROM ABC LEFT JOIN ABC_values USING (id) NATURAL JOIN (
SELECT id FROM ABC_values WHERE content = 'value 5'
) t
GROUP BY id
If it is completely impossible to change the schema, you can try FIND_IN_SET():
SELECT * FROM ABC WHERE FIND_IN_SET('value 5', content)
Another workaround is to use LIKE with the delimiters of the items in your list:
WHERE content LIKE ',5,'
But the item you're looking for may be at the start or end of the list. So you have to modify the list on the fly to include the delimiters at the start and end.
WHERE CONCAT(',', content, ',') LIKE '%,5,%' -> this works for me on mysql
This works, and in some sense it's no worse than any other search that you do for an item in a comma-separated list. That's because such a search is bound to do a table-scan and therefore it's very inefficient. As the data in your table grows, you'll find it can't perform well enough to be useful.
See also my answer to Is storing a delimited list in a database column really that bad?