Related
I have three tables. FirstTable is like this:
id
id2
id3
message
info
1
0
2
hello!
none
2
1
0
hi there
none
3
0
3
hi man
none
SecondTable is:
id2
name
1
Alex
2
Bob
ThirdTable is:
id3
name
1
Rob
2
Tom
3
Joe
As you can see, in FirstTable always only one of id2 and id3 column's values is not zero. So, I want to get the result as below:
1 - Tom - hello!
or
2 - Alex - hi there
or
3 - Joe - hi man
I cannot use a query like
SELECT
FirstTable.id AS id, FirstTable.message AS message,
FirstTable.info AS info,
SecondTable.name AS name1,
ThirdTable.name AS name2,
FROM
FirstTable, SecondTable, ThirdTable
WHERE
FirstTable.id = 1
AND FirstTable.id2 = SecondTable.id2
AND FirstTable.id3 = ThirdTable.id3
ORDER BY
FirstTable.id DESC
because I do not have 0 only one of id2/id3 in FirstTable. What is the right query to get something like
1 - Tom - hello!
? Thanks
You can accoumplish that by using two LEFT JOINs
CREATE TABLE table1
(`id` int, `id2` int, `id3` int, `message` varchar(8), `info` varchar(4))
;
INSERT INTO table1
(`id`, `id2`, `id3`, `message`, `info`)
VALUES
(1, 0, 2, 'hello!', 'none'),
(2, 1, 0, 'hi there', 'none'),
(3, 0, 3, 'hi man', 'none')
;
CREATE TABLE table2
(`id2` int, `name` varchar(4))
;
INSERT INTO table2
(`id2`, `name`)
VALUES
(1, 'Alex'),
(2, 'Bob')
;
CREATE TABLE table3
(`id3` int, `name` varchar(3))
;
INSERT INTO table3
(`id3`, `name`)
VALUES
(1, 'Rob'),
(2, 'Tom'),
(3, 'Joe')
;
SELECT t1.`id`,
CASE WHEN t1.id2 = 0 THEN t3.`name`
ELSE t2.`name`END name,
t1.message
FROM table1 t1 LEFT JOIN table2 t2 ON t1.id2=t2.id2 LEFT JOIN table3 t3 ON t1.id3 = t3.id3
id | name | message
-: | :--- | :-------
1 | Tom | hello!
2 | Alex | hi there
3 | Joe | hi man
db<>fiddle here
Table 1
|id|name|address|car_id |
|1 |Alex|US |NULL |
|2 |Jaso|Canada |1 |
Table 2
|car_id|color|
|1 |red |
|2 |blue |
I am trying to update Alex's car_id with the car_id of the blue car in the second table. Is it possible to do it in one query?
I tried writing the query below, but couldn't make it work. Any ideas?
UPDATE table1
SET table1.car_id = table2.car_id
FROM table1
JOIN table2
ON table2.color = "blue"
WHERE table1.name = "Alex"
Desired result:
|id|name|address|car_id |
|1 |Alex|US |2 |
|2 |Jaso|Canada |1 |
I suspect it does not work in one query. [Edit: Wrong, see other answer]
You have 2 different requirements for 2 different tables which do not have a common column.
You need to find the blue car_id independently from Alexes row as they are not linked in any way by now.
I would do it as follows:
UPDATE
table1
SET
table.car_id = (
SELECT
car_id
FROM
table2
WHERE
color LIKE 'blue'
)
WHERE
name LIKE 'Alex'
update firstTable join secondTable on secondTable.color = 'blue' set firstTable.car_id = secondTable.car_id where firstTable.car_id is null;
I have a solution for a similar problem with more people and more cars.
Maybe it helps DBfiddle example
The base datatabke are as follows
CREATE TABLE Table1
(`id` int, `name` varchar(4), `address` varchar(7), `car_id` varchar(4))
;
INSERT INTO Table1
(`id`, `name`, `address`, `car_id`)
VALUES
(1, 'Alex', 'US', NULL),
(2, 'Jaso', 'Canad a', '1'),
(3, 'Paso', 'Canad a', NULL),
(4, 'Paso', 'danad a', NULL)
;
CREATE TABLE Table2
(`car_id` int, `color` varchar(7))
;
INSERT INTO Table2
(`car_id`, `color`)
VALUES
(1, 'red'),
(2, 'blue'),
(3, 'green') ,
(4, 'purple')
;
The sql statement for mysql till 5.7
Update Table1 t1a inner Join
(Select tab1.id, tab2.car_id From
( Select
`id`,
#curRank := #curRank + 1 AS rank
FROM Table1, (SELECT #curRank := 0) r
WHERE car_id IS NULL ) tab1
inner join
( Select
car_id,
#curRank2 := #curRank2 + 1 AS rank
From Table2 , (SELECT #curRank2 := 0) r Where car_id NOT IN
(
Select Car_id From
(Select GROUP_CONCAT(t1.car_id) car_id FROM Table1 as t1) t1e
WHERE car_id IS NOT NULL GROUP BY car_id
)
) tab2
ON tab1.rank = tab2.rank) t2a
on t1a.id = t2a.id
SET t1a.car_id = t2a.car_ID
;
The Problem that we face here is that we need actually the car_ids from table taht are already taken. And then select only rest of the car_id, that are not selected yet.
After that we have to make the statement so that ver person gets one color ann that every colour is selected only once. that takes a little code because we have no relationship betwenn tabel1 car_ids thta are NULL and table2.
So result is
id name address car_id
1 Alex US 2
2 Jaso Canad a 1
3 Paso Canad a 3
4 Paso danad a 4
With mysql 8 you use window function instead of the vehicle rank.
I have a difficult task to build up an array retrieved from a table similar to the one below:
table_a
id | scenario_id | entity_id
1 1;2;3;4;5 1;3
2 4;5;8;10 2;3
3 1;5;8;11 1;2;4;
4 3;5;8;9 4;5;
Now, if one user selects from one entity_id, let's say 3, the SQL query should return something similiar to:
scenario_id
1;2;3;4;5;8;10
Or, if he selects 5, the returned array should look like:
scenario_id
3;5;8;9
Could that be done using only SQL statements?
For SQL Server you can use this to get desired output:
DECLARE #xml xml, #entity_id int = 3
--Here I generate data similar to yours
;WITH cte AS (
SELECT *
FROM (VALUES
(1, '1;2;3;4;5', '1;3'),
(2, '4;5;8;10', '2;3'),
(3, '1;5;8;11', '1;2;4;'),
(4, '3;5;8;9', '4;5;')
) as t(id, scenario_id, [entity_id])
)
--create xml
SELECT #xml = (
SELECT CAST('<i id="'+ CAST(id as nvarchar(10)) +'"><s>' + REPLACE(scenario_id,';','</s><s>') + '</s><e>' + REPLACE([entity_id],';','</e><e>') + '</e></i>' as xml)
FROM cte
FOR XML PATH('')
)
--Normalizing the table and getting result
SELECT STUFF((
SELECT ';' + CAST(scenario_id as nvarchar(10))
FROM (
SELECT DISTINCT t.v.value('.','int') as scenario_id
FROM #xml.nodes('/i/s') as t(v)
INNER JOIN #xml.nodes('/i/e') as s(r)
ON t.v.value('../#id','int') = s.r.value('../#id','int')
WHERE s.r.value('.','int') = #entity_id
) as p
FOR XML PATH('')),1,1,'') as scenario_id
Output for entity_id = 3:
scenario_id
1;2;3;4;5;8;10
For entity_id = 5
scenario_id
3;5;8;9
you can use something like this to find a id in the scenario_id, but its always a FULL TABLE scan.
SELECT *
FROM table_a
WHERE
FIND_IN_SET('3', REPLACE(scenario_id,';',',')) > 0;
Simple. NORMALISE your schema... At it's crudest, that might be as follows...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id INT NOT NULL
,scenario_id INT NOT NULL
,entity_id INT NOT NULL
,PRIMARY KEY (id,scenario_id,entity_id)
);
INSERT INTO my_table VALUES
(1, 1,1),
(1, 1,3),
(1, 2,1),
(1, 2,3),
(1, 3,1),
(1, 3,3),
(1, 4,1),
(1, 4,3),
(1, 5,1),
(1, 5,3),
(2, 4,2),
(2, 4,3),
(2, 5,2),
(2, 5,3),
(2, 8,2),
(2, 8,3),
(2,10,2),
(2,10,3),
(3, 1,1),
(3, 1,2),
(3, 1,4),
(3, 5,1),
(3, 5,2),
(3, 5,4),
(3, 8,1),
(3, 8,2),
(3, 8,4),
(3,11,1),
(3,11,2),
(3,11,4),
(4, 3,4),
(4, 3,5),
(4, 5,4),
(4, 5,5),
(4, 8,4),
(4, 8,5),
(4, 9,4),
(4, 9,5);
SELECT DISTINCT scenario_id FROM my_table WHERE entity_id = 3 ORDER BY scenario_id;
+-------------+
| scenario_id |
+-------------+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 8 |
| 10 |
+-------------+
split the scenario_id by ';' and copy to temporary table to use that for your query use instr and substring functions
this link may help you but you need a loop function to call your procedure as the ';' is repeated
I want to do subquery with 3 tables and using where in multi values but I always get syntax error. I have to do reporting in Report Builder 3.0
Table A: record_id, Surname, Given Name
Table C: row_id, competency_code, competency_name
Table PC: link_id, record_id, row_id, attainment_date
I would like to join the tables into 1 table. One person will have some completion of competency_code and different with other person. the completion of competency_code based on the attainment_date. I also think to use iff function for attainment_date in competency_code value as complete/yes.
The table that I would like to create is:
Record_Id | Surname | GivenName | Code 1 | Code 2 | Code 3 | Code 4 | Code 5
01 | AA | AA | Complete | Complete | Complete | | Complete
02 | BB | BB | Complete | Complete | | Complete |
03 | CC | CC | | Complete | Complete | | Complete
here is the query that I tried to do.
select distinct a.id, a.surname, a.given_name
from all a
join
(
select pc.attainment_date
from personnel_competency pc
join
(
select c.code, c.name
from competency c)
competency c on (c.row_no = pc.linkid)
)
personnel_competency pc on (pc.id = a.id)
where c.code in ('ABC', 'BCD', 'ABE', 'DEA', 'DEF', 'POS', 'SAQ', 'LOP')
and pc.attainment_date < now()
order by a.record_id
My skill in SQL is very basic. Whether other ways to make the table like that?
Are you looking for a SQL to get your result. If so I think this is what you are looking for ..
It would help if you posted some sample data.
You can test it at
SQLFiddle
Here is the script ..
-- Generate schema and data
create table tableA (id int, surname varchar(30), given_name varchar(30));
create table tablePC (link_id int, id int, attainment_date datetime);
create table tableC (row_id int, competency_code varchar(20), Competency_name varchar(30));
insert into tableA (id, surname, given_name)
values (1, 'AA', 'AAgn')
, (2, 'BB', 'BBgn')
insert into tablePC (link_id, id, attainment_date)
values (1, 1, '2014-09-11')
, (2, 1, '2014-09-10')
, (3, 2, '2014-09-11')
insert into tableC (row_id, competency_code, Competency_name)
values (1, 'ABC', 'completed\Yes')
, (1, 'BCD', 'completed')
, (1, 'ABE', 'completed')
, (2, 'ABC', 'completed')
, (2, 'BCD', 'completed')
, (3, 'ABC', 'completed')
, (3, 'ABE', 'completed')
-- ===============
select *
from tableA TA
inner join tablePC PC
on TA.id = PC.id
inner join
(
select row_id, [ABC] as ABC, [BCD] as BCD, [ABE] as ABE
from tableC TC
pivot
(
max(Competency_name)
for Competency_code in ([ABC], [BCD], [ABE])
) as TCPVT
) TC
on PC.link_id = TC.row_id
where PC.attainment_date < GETDATE()
In MySQL, I have two tables with a 1:n relationship.
Table items has products, whose state is kept in another table, like so :
items:
id |ref_num|name |...
1 |0001 |product1|...
2 |0002 |product2|...
items_states :
id|product_id|state_id|date
1 |1 |5 |2010-05-05 10:25:20
2 |1 |9 |2010-05-08 12:38:00
3 |1 |6 |2010-05-10 20:45:12
...
The states table is not relevant and only relates the state_id to the state name and so on.
How can I get products where the latest state is the one I specify, one item per row?
Thank you
You may want to try the following:
SELECT i.ref_num, i.name, s.latest_date
FROM items i
JOIN (
SELECT product_id, MAX(date) as latest_date
FROM items_states
GROUP BY product_id
) s ON (s.product_id = i.id);
If you want to return just one item, simply add a WHERE i.id = ? to the query.
Test case:
CREATE TABLE items (id int, ref_num varchar(10), name varchar(10));
CREATE TABLE items_states (id int, product_id int, state_id int, date datetime);
INSERT INTO items VALUES (1, '0001', 'product1');
INSERT INTO items VALUES (2, '0002', 'product2');
INSERT INTO items_states VALUES (1, 1, 5, '2010-05-05 10:25:20');
INSERT INTO items_states VALUES (2, 1, 9, '2010-05-08 12:38:00');
INSERT INTO items_states VALUES (3, 1, 6, '2010-05-10 20:45:12');
Result:
+---------+----------+---------------------+
| ref_num | name | latest_date |
+---------+----------+---------------------+
| 0001 | product1 | 2010-05-10 20:45:12 |
+---------+----------+---------------------+
1 row in set (0.02 sec)
Either LEFT JOIN the items_states table to itself, requiring a second.date > first.date, and put a WHERE second.id IS NULL clause in it:
SELECT a.*
FROM item_states a
LEFT JOIN item_states b
ON a.product_id = b.product_id
AND b.product_id > a.product_id
WHERE b.id IS NULL AND a.state_id = <desired state>
Or make a row based query: see Mark Byers' example.