Conditional Table change in MySQL Query - mysql

I tried to work out around this. But I think I am getting no where.
I have 3 tables:
This tale contains all questions and question types:
Table: Ref
id | type | info
==========================
1 SS Education
---------------------------
2 RB Gender
---------------------------
3 ST State
This table contains "options" for the questions in the above table 'Ref`
Table: ref_ans
id | q_id | answer_text
===========================
1 1 Masters
---------------------------
2 1 Bachelors
---------------------------
3 1 Undergrad
---------------------------
4 2 Male
---------------------------
5 2 Female
---------------------------
6 2 Dont want to disclose
This table contains states (type ="ST" in table Ref)
Table: us_states
id | answer_text
===========================
1 Alaska
---------------------------
2 Alabama
---------------------------
3 Arkansan
---------------------------
4 Arizona
---------------------------
5 Baltimore
---------------------------
etc
The result I want is:
ref.id, ref_ans.id, ref.answer_text / us_states.answer_text
*for a given ref.question_id *.
And the condition is: If the question_id, for which the answers requested is 'ST', it should pull the answers from us_states, otherwise, it should pull from ref-ans table.
I tried this. Obviously, this did not work:
SELECT ref.id,
CASE WHEN ref.type = 'ST' THEN
(SELECT ID, answer_text FROM us_states )
ELSE
(SELECT id, answer_text FROM ref_ans)
END
FROM ref
WHERE ref.ID = <id>
Any ideas?

Try:
SELECT a.id,
COALESCE(b.id, c.id) AS ans_id,
COALESCE(b.answer_text, c.answer_text) AS answer_text
FROM ref a
LEFT JOIN ref_ans b ON a.id = b.q_id
LEFT JOIN us_states c ON a.type = 'ST'
WHERE a.id = <id> AND (
(a.type <> 'ST' AND b.id IS NOT NULL) OR
(a.type = 'ST' AND c.id IS NOT NULL)
)

Assuming all the three tables are connected by id(1st column):
SELECT ref_ans.id, ref.id, if(ref.type='ST', us_states.answer_text, ref_ans.answer_text) as answer_text
FROM ref_ans
JOIN ref on ref.id=ref_ans.id
JOIN us_states on ref.id=us_states.id
WHERE ref_ans.q_id = <id>

Related

MYSQL Query - Find rows where multiple ID match, but states are different

I have 2 databases, 1 with order number (orders)
| id | reference | ....
1 12345678 ....
2 12345679 ....
and another with order_state_history (order_history)
| id | id_order | order_state | ....
1 1 3
1 1 7
1 1 5
2 1 3
2 1 7
2 1 1
And I need to get all order references that have had 1 specific order_state in the order_history, but NEVER had some other states
For example, all order that have had state 3 and 7, but never had state 5. (only should return the reference from order id 2)
I tried some random simple queries like, but without any luck, if someone can help me with this it would be really much appreciated.
[Here where my attempts, I don't have much experience with SQL]
SELECT
p.id_order,
p.reference,
o.id_order_state AS "state_a",
b.id_order_state AS "state_b"
FROM
order_history o
JOIN orders p
ON o.id_order = p.id_order
JOIN order_history AS b
ON p.id_order = b.id_order
WHERE o.id_order_state = 76 AND b.id_order_state = 4 AND b.id_order_state NOT IN (26,20,22,23)
Thank for your time!
Your question is rather poorly phrased but you can use aggregation and a having clause:
select order_id
from order_state
group by order_id
having sum(state = 3) > 0 and
sum(state = 7) > 0 and
sum(state = 5) = 0;

How to display a query in a certain way?

I'm currently new to queries and below I have a query that I have made
QUERY:
select TITLE_ID, TITLE,NAME, JOB_CATEGORY AS ROLE
FROM MOVIES
NATURAL JOIN NEW_NAMES
WHERE JOB_CATEGORY = 'writer'
OR JOB_CATEGORY = 'director'
ORDER BY TITLE_ID ASC;
Which Displays:
TITLE_ID | TITLE | NAME | ROLE |
753595 | 2F2F | ROB | WRITER |
753595 | 2F2F | YAS | DIRECTOR|
However I would like it to display in this format below:
TITLE_ID | TITLE | WRITER | DIRECTOR|
753595 | 2F2F | ROB | YAS |
You join your NEW_NAMES table in twice. Once for director, once for writer. When you join a table more than once it's necessary that you give the table an Alias, here we use writer and director.
select TITLE_ID, TITLE,writer.NAME as writer_name, director.NAME as director_name
FROM MOVIES
LEFT OUTER JOIN NEW_NAMES as writer
ON MOVIES.TITLE_ID = writer.TITLE_ID
AND writer.JOB_CATEGORY = 'writer'
LEFT OUTER JOIN NEW_NAMES as director
ON MOVIES.TITLE_ID = director.TITLE_ID
AND director.JOB_CATEGORY = 'director'
ORDER BY TITLE_ID ASC;
I've made some assumptions in those ON clauses about which columns in your tables you are joining on. You may need to edit that.
According to error message you got, it is about Oracle, not MySQL.
Anyway, such a (classic?) principle should work: aggregate!
SQL> with
2 -- sample data
3 movies (title_id, title_name) as
4 (select 753595, '2F2F' from dual union all
5 select 123456, '1Z1Z' from dual
6 ),
7 new_names (title_id, job_category, name) as
8 (select 753595, 'writer', 'ROB' from dual union all
9 select 753595, 'director', 'YAS' from dual
10 )
11 -- query you need
12 select m.title_id,
13 m.title_name,
14 max(case when n.job_category = 'writer' then n.name end) as writer,
15 max(case when n.job_category = 'director' then n.name end) as director
16 from movies m left join new_names n on m.title_id = n.title_id
17 group by m.title_id, m.title_name
18 order by m.title_id;
TITLE_ID TITL WRI DIR
---------- ---- --- ---
123456 1Z1Z
753595 2F2F ROB YAS
SQL>

SQL Select parent as column name and child as value

I am creating a database to store music.
There are different categories that each have sub categories. Example:
id name parentID
1 instrumentation null
2 solo_instrument null
3 Concert Band 1
4 Brass Band 1
5 Fanfare Band 1
6 Clarinet 2
7 Saxophone 2
8 Trumpet 2
On the other hand I have a table that stores the musicID that is linked to a categoryID
id categoryID musicID
1 4 1
2 8 1
3 3 2
4 6 2
I need the following result from a query:
musicID instrumentation solo_instrument
1 Brass Band Trumpet
2 Concert Band Clarinet
I have been told to use a tree structure as in the future it is likely that other categories are added and this should be able to support that. However, I am not able to figure out how to write a query to get the result above.
I kind of get the result I want when selecting first the instrumentation, second the solo_instrument, but this is all hardcoded and does not allow for music tracks to only have one parentID as I select them individually.
Is this even possible or should I overhaul my database structure? I'd like to see your recommendations.
You should be able to tackle this using conditional aggregation.
Query :
SELECT
mu.musicID,
MAX(CASE WHEN cp.name = 'instrumentation' THEN ca.name END) instrumentation,
MAX(CASE WHEN cp.name = 'solo_instrument' THEN ca.name END) solo_instrument
FROM
musics mu
INNER JOIN categories ca ON ca.id = mu.categoryID
INNER JOIN categories cp ON cp.id = ca.parentID
GROUP by mu.musicID
The INNER JOINs pull up the corresponding category, and then goes up one level to find the parent category. If new root categories are created, you would just need to add more MAX() columns to the query.
In this DB Fiddle demo with your sample data, the query returns :
| musicID | instrumentation | solo_instrument |
| ------- | --------------- | --------------- |
| 1 | Brass Band | Trumpet |
| 2 | Concert Band | Clarinet |
First you group by musicid in table_music and the join twice to table_categories:
select t.musicid, c1.name instrumentation, c2.name solo_instrument
from (
select musicid, min(categoryid) instrumentationid, max(categoryid) solo_instrumentid
from table_music
group by musicid
) t inner join table_categories c1
on c1.id = t.instrumentationid
inner join table_categories c2
on c2.id = t.solo_instrumentid
order by t.musicid

Select from one table but filtering other two

Let's say i've got this database:
book
| idBook | name |
|--------|----------|
| 1 |Book#1 |
category
| idCateg| category |
|--------|----------|
| 1 |Adventures|
| 2 |Science F.|
book_categ
| id | idBook | idCateg | DATA |
|--------|--------|----------|--------|
| 1 | 1 | 1 | (null) |
| 2 | 1 | 2 | (null) |
I'm trying to select only the books which are in category 1 AND category 2 something like this
SELECT book.* FROM book,book_categ
WHERE book_categ.idCateg = 1 AND book_categ.idCateg = 2
Obviously, this giving 0 results becouse each row has only one idCateg it does work width OR but the results are not what I need. I've also tried to use a join, but I just can't get the results I expect.
Here it's the SQLFiddle of my current project, with my current DB, the data at the begining is just a sample. SQLFiddle
Any help will be really appreciated.
Solution using EXISTS:
select *
from book b
where exists (select 'x'
from book_categ x
where x.idbook = b.idbook
and x.idcateg = 1)
and exists (select 'x'
from book_categ x
where x.idbook = b.idbook
and x.idcateg = 2)
Solution using join with an inline view:
select *
from book b
join (select idbook
from book_categ
where idcateg in (1, 2)
group by idbook
having count(*) = 2) x
on b.idbook = x.idbook
You could try using ALL instead of IN (if you only want values that match all criteria to be returned):
SELECT book.*
FROM book, book_categ
WHERE book_categ.idCateg = ALL(1 , 2)
One way to get the result is to do join to the book_categ table twice, something like
SELECT b.*
FROM book b
JOIN book_categ c1
ON c1.book_id = b.id
AND c1.idCateg = 1
JOIN book_categ c2
ON c2.book_id = b.id
AND c2.idCateg = 2
This assumes that (book_id, idCateg) is constrained to be unique in the book_categ table. If it isn't unique, then this query can return duplicate rows. Adding a GROUP BY clause or the DISTINCT keyword will eliminate any generated duplicates.
There are several other queries that can get generate the same result.
For example, another approach to finding book_id that are in two categories is to get all the rows with idCateg values of 1 or 2, and then GROUP BY book_id and get a count of DISTINCT values...
SELECT b.*
FROM book b
JOIN ( SELECT d.book_id
FROM book_categ d
WHERE d.idCateg IN (1,2)
GROUP BY d.book_id
HAVING COUNT(DISTINCT d.idCateg) = 2
) c
ON c.book_id = b.id

JOIN on array of ids in sql

I have three tables:
TABLE 1 contracts
-------------------
id | contract_name
--------------------
1 test name
2 test name 2
2 test name 3
4 test name 4
TABLE 2 rooms
-------------------
id | room_name
--------------------
1 test name
2 test name 2
2 test name 3
4 test name 4
TABLE 3 promos
----------------------------------
id | contracts_id | rooms_id
----------------------------------
1 1,3 1,3,4
1 2 1,2,3
No I am trying to do an inner join to get the names of the contract and the rooms according to the ids in the array saved in database. I know this is not ideal at all, but I can not change the database set up. So here is what I would like to do with my query, but obviously it is impossible. Does anyone have any idea on how I can accomplish this?
mysql_query("SELECT pb.*, c.contract_name, r.room_name FROM promo_blackouts AS pb
INNER JOIN contracts as c ON c.contract_id IS IN pb.contracts_id
INNER JOIN rooms as r ON r.room_id IS IN pb.rooms_id
WHERE pb.promo_id = '$promo_id'") or die(mysql_error());
Are you looking for something like this?:
SELECT DISTINCT
contract_name,
room_name
FROM
promos
INNER JOIN
contracts ON FIND_IN_SET(contracts.id, contract_id) != 0
INNER JOIN
rooms ON FIND_IN_SET(rooms.id, room_id) != 0
WHERE
promos.id = 1