MySQL update table from a EAV table using case when - mysql

I have a EAV table. I want to convert this into a normal table in a single query. How can I do this?
Table A
| ID | Entity | Attribute |
+----+--------+-----------+
| 1 | AA | 5 |
| 2 | AA | 2 |
| 3 | AA | 4 |
| 1 | BB | 6 |
| 2 | BB | 5 |
Table B (intended. This has only ID as of now)
| ID | AA | BB |
+----+-----+------+
| 1 | 5 | 6 |
| 2 | 2 | 5 |
| 3 | 4 | NULL |
I tried the following:
update B join A using(ID) set b.AA=(case when Entity='AA' then Attribute end),b.BB=(case when Entity='BB' then Attribute end);
update B join A using(ID) set b.AA=(case when Entity='AA' then Attribute else AA end),b.BB=(case when Entity='BB' then Attribute else BB end);
But the table is not getting updated. Both the fields are set to NULL for all the IDs. I can write separate update queries for each Entity, but I have >100 different entities and each query takes hours to run (I have many records).

Related

Update MySQL table with smallest value from another table

I have been looking around quite a lot but I can't seem to find a solution to this problem.
I got two tables:
|---------------------|-------------------|
| ID | Value |
|---------------------|-------------------|
| 1 | NULL |
| 2 | NULL |
| 3 | NULL |
| 4 | NULL |
|---------------------|-------------------|
...
|---------------------|-------------------|
| ID | Value |
|---------------------|-------------------|
| 1 | 7 |
| 1 | 18 |
| 2 | 21 |
| 2 | 2 |
| 4 | 103 |
|---------------------|-------------------|
...
Basically what I wanna do is update the NULL-fields from the first table with the smallest value from the second table where there are matching IDs.
So that in the end it looks something like this:
|---------------------|-------------------|
| ID | Value |
|---------------------|-------------------|
| 1 | 7 |
| 2 | 2 |
| 3 | NULL |
| 4 | 103 |
|---------------------|-------------------|
...
I tired out a bunch of things but failed. Can anyone help me?
You could use a sub query:
update t1
inner join (select ID, min(Value) as minimum from t2 group by ID) tempt2 on t1.ID=tempt2.ID
set t1.value=tempt2.minimum;
Basically, you're looking up that minimum value in the second table for each ID, you call that table tempt2, and you join on that.

mysql Select values from multiple columns into single column

I have a table in a database that has several columns containing the same sort of data, these values are allowed to be null. I need to select each of the non-null values into a single column of values that care about the identity of the row from which they originated.
So, for a table that looks like this:
+---------+------+--------+------+
| Id | name | v1 | v2 |
+---------+------+--------+------+
| 1 | eko | aa | bb |
| 2 | agus | null | cc |
| 3 | eko | dd | null|
| 4 | budi | aa | null|
| 5 | siti | ff | gg |
+---------+------+--------+------+
I wish to select each of the values aa,bb,cc, etc into a single column. My result data should look like the following table.
+-------+-------+-------+
| id | name | v |
+-------+-------+-------+
| 1 | eko | aa |
| 1 | eko | bb |
| 2 | agus | cc |
| 3 | eko | dd |
| 4 | budi | aa |
| 5 | siti | ff |
| 5 | siti | gg |
+-------+-------+-------+
I am using mysql. Is there a technique for achieving this with respect to performance too?
You could just use two queries and use the union statement of the two to append the two sets:
Select id, v1 as v
From table
where v1 is not null
union all
select id, v2 as v
from table
where v2 is not null
But to make this dynamic (any number of v...) you would have to iterate over the columns. See:mysql, iterate through column names

Merge 2 different mysql tables

I have two tables:
Table a:
+----+------+
| id | data |
+----+------+
| 1 | 450 |
| 2 | 500 |
| 3 | 550 |
| 4 | 600 |
| 5 | 650 |
+----+------+
Table b:
+----+------+------+
| id | a_id | note |
+----+------+------+
| 1 | 2 | 25 |
| 2 | 5 | 10 |
+----+------+------+
I need a query that returns a table that consists of every row from table a with the notes from table b. I want 0 filled in where a note isn't available on a row. I want it to look like this:
+----+------+------+
| id | data | note |
+----+------+------+
| 1 | 450 | 0 |
| 2 | 500 | 25 |
| 3 | 550 | 0 |
| 4 | 600 | 0 |
| 5 | 650 | 10 |
+----+------+------+
How do I do that?
select a.id, a.data, coalesce(b.note, 0) as note
from a
left join b on a.id = b.a_id
What are you looking for is called LEFT/RIGHT JOIN. This question will give you more details about what they are.
Assume you have a query like:
SELECT * FROM a LEFT JOIN b ON some_condition;
Then, its output will contain every row from table a, along with data from table b where the condition is met. For rows where the condition is not met, the columns with data from b will contain null.

MySql Update Row and it's "Descendants"

I'm having trouble figuring out how to update the descendants/children of a row.
Example table, named test
+----+--------+------+
| Id | Parent | Val |
+----+--------+------+
| 1 | 0 | |
| 2 | 1 | |
| 3 | 1 | |
| 4 | 1 | |
| 5 | 0 | |
| 6 | 5 | |
| 7 | 6 | |
| 8 | 6 | |
| 9 | 0 | |
+----+--------+------+
What I'd like to have done is, when Val is set to something, update every row that is related to that row. For example, If I ran
UPDATE test SET Val=1 WHERE Id=5;
I want Val in the rows where the Id is 6, 7, and 8, to also be 1.
The best thing I could come up with was
UPDATE test t1
JOIN test t2 ON t1.Id = t2.Parent
JOIN test t3 ON t2.Id = t3.Parent
SET t1.Val=1, t2.Val=1, t3.Val=1 WHERE t1.Id=5;
+----+--------+------+
| Id | Parent | Val |
+----+--------+------+
| 1 | 0 | |
| 2 | 1 | |
| 3 | 1 | |
| 4 | 1 | |
| 5 | 0 | 1 |
| 6 | 5 | 1 |
| 7 | 6 | 1 |
| 8 | 6 | 1 |
| 9 | 0 | |
+----+--------+------+
This gives me what I want, but I'm afraid it's poor practice and it doesn't account for a variable depth. What can I do here? I thought a trigger may have been the answer, but that didn't seem to be possible. I got the error "Can't update table in stored function/trigger because it is already used by statement which invoked this stored function/trigger"
It's pretty awkward to handle this kind of case with MySQL, because MySQL doesn't support recursive queries.
I solve this problem by storing the hierarchy as a transitive closure, instead of the "parent_id" style you're using. See my answer to What is the most efficient/elegant way to parse a flat table into a tree?
Then you can update all descendants of a given node in the heirarchy:
UPDATE test JOIN testclosure AS c ON test.id = c.descendant
SET test.val = 1
WHERE c.ancestor = 5;

Select Distinct Set Common to Subset From Join Table

Given a join table for m-2-m relationship between booth and user
+-----------+------------------+
| booth_id | user_id |
+-----------+------------------+
| 1 | 1 |
| 1 | 2 |
| 1 | 5 |
| 1 | 9 |
| 2 | 1 |
| 2 | 2 |
| 2 | 5 |
| 2 | 10 |
| 3 | 1 |
| 3 | 2 |
| 3 | 3 |
| 3 | 4 |
| 3 | 6 |
| 3 | 11 |
+-----------+------------------+
How can I get a distinct set of booth records that are common between a subset of user ids? For example, if I am given user_id values of 1,2,3, I expect the result set to include only booth with id 3 since it is the only common booth in the join table above between all user_id's provided.
I'm hoping I'm missing a keyword in MySQL to accompish this. The furthest I've come so far is using ... user_id = all (1,2,3) but this is always returning an empty result set (I believe I understand why it is though).
The SQL query for this will be:
select booth_id from table1 where [user_id]
in (1,2,3) group by booth_id having count(booth_id) =
(select count(distinct([user_id])) from table1 where [user_id] in (1,2,3))
If this could help you creating the MySQL query.