I've got three tables in MySQL: wp_usermeta, directory_department, and directory_departmentmemebership
Directory_departmentmembership
| employee_id|department_id|
|:-----------|------------:|
| 1 | 2 |
| 2 | 1 |
| 3 | 3 |
directory_department
| department_id|department_name|
|:----------- |--------------:|
| 1 | Deans |
| 2 | MBA |
| 3 | Fiance |
wp_usermeta has:
| employee_id| meta_key | meta_value |
|:-----------|--------------:|:------------:|
| 1 |department_id | 2 |
| 2 |department_id | 1 |
| 3 |department_id | 3 |
| 1 |department_name| |
| 2 |department_name| |
| 3 |department_name| |
How I can I reference directory_department to insert the correct department_name based off of the department_id value in the meta_value field?
You can use a SQL function to get the right name for each id...
CREATE FUNCTION [dbo].[fn_department](#id INT)
RETURNS VARCHAR(300)
AS
BEGIN
declare #department_name varchar(300)
select #department_name = department_name from directory_department where department_id = #id
RETURN #department_name
END
--And call it like this...
INSERT INTO wp_usermeta (id,department_name)
select id, dbo.fn_department(id) as department_name
Related
+--------------+
| paintings |
+--------------+
| id | title |
+----+---------+
| 1 | muzelf1 |
| 2 | muzelf2 |
| 3 | muzelf3 |
+----+---------+
+----------------------------------------+
| tags |
+----------------------------------------+
| id | type | name |
+----+-----------------+-----------------+
| 1 | painting_medium | oil_painting |
| 2 | painting_style | impressionistic |
| 3 | painting_medium | mixed_media |
| 4 | painting_medium | watercolours |
| 5 | painting_style | mixed_media |
| 6 | painting_style | photorealistic |
+----+-----------------+-----------------+
+---------------------------+
| paintings_tags |
+---------------------------+
| id | painting_id | tag_id |
+----+-------------+--------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 4 |
| 4 | 3 | 2 |
| 5 | 3 | 1 |
+----+-------------+--------+
sql
CREATE TABLE paintings (
id integer AUTO_INCREMENT PRIMARY KEY,
title text
);
INSERT INTO paintings(id,title) VALUES
(1,'muzelf1'),(2,'muzelf2'),(3,'muzelf3');
CREATE TABLE tags (
id integer AUTO_INCREMENT PRIMARY KEY,
name text,
type text
);
INSERT INTO tags(id,name,type) VALUES
(1,'oil_painting','painting_medium')
,(2,'impressionistic','painting_style')
,(3,'mixed_media','painting_medium')
,(4,'watercolours','painting_medium')
,(5,'mixed_media','painting_style')
,(6,'photorealistic','painting_style');
CREATE TABLE paintings_tags (
id integer AUTO_INCREMENT PRIMARY KEY,
painting_id integer,
tag_id integer
);
INSERT INTO paintings_tags(id,painting_id,tag_id) VALUES
(1,1,1)
,(2,1,2)
,(3,2,4)
,(4,3,2)
,(5,3,1);
Find all the paintings with [{tags.type="painiting_medium", tags.name="oil_painitng"},{tags.type="painiting_style", tags.name="impressionistic"}].
+-----------------------------------+
| Expected Output |
+-----------------------------------+
| id | painting_title | painting_id |
+----+----------------+-------------+
| 1 | muzelf1 | 1 |
+----+----------------+-------------+
| 2 | muzelf3 | 3 |
+----+----------------+-------------+
Here is something I tried doing using bookShelf ORM and knex query builder.
Painting.query(function (qb) {
qb.innerJoin('painting_tags','paintings.id','painting_tags.painting_id')
.innerJoin('tags','painting_tags.tag_id','tags.id')
.where(qb => {
tagFilters.forEach(filter => {
qb.where('tags.type',filter.type).andWhere('tags.name',filter.name)
})
});
});
The above only works if the tag filters array has only one element. But I need it to work for all the filters in the array.
What would a raw query look like for the above? And how can I convert the same to work using ORM and query builder?
Here's one idea:
SELECT p.id painting_id
, p.title
, MAX(CASE WHEN t.type = 'painting_medium' THEN t.name END) medium
, MAX(CASE WHEN t.type = 'painting_style' THEN t.name END) style
FROM paintings p
JOIN paintings_tags pt
ON pt.painting_id = p.id
JOIN tags t
ON t.id = pt.tag_id
GROUP
BY p.id;
+-------------+---------+--------------+-----------------+
| painting_id | title | medium | style |
+-------------+---------+--------------+-----------------+
| 1 | muzelf1 | oil_painting | impressionistic |
| 2 | muzelf2 | watercolours | NULL |
| 3 | muzelf3 | oil_painting | impressionistic |
+-------------+---------+--------------+-----------------+
You could filter this as a subquery (or using HAVING) but, unless the data set was vast, I would be inclined to do the filtering in a bit of javascript.
I have a table: Accounts
+-----------+-----------------+------+
| AccountNo | ParentAccountNo | name |
+-----------+-----------------+------+
| 1 | null | ABC |
| 2 | 1 | ABCD |
| 3 | 1 | CDE |
| 4 | 2 | DEF |
| 5 | null | GHI |
| 6 | 3 | MNO |
| 7 | 5 | JKL |
+-----------+-----------------+------+
I need to get results where AccountNo does not exist in ParentAccountNo.
For example, based on the data above, the results I expect are:
+-----------+-----------------+------+
| AccountNo | ParentAccountNo | name |
+-----------+-----------------+------+
| 4 | 2 | DEF |
| 6 | 3 | MNO |
| 7 | 5 | JKL |
+-----------+-----------------+------+
Will accept answer for MySQL or SQL-Server.
By joining the table to itself with a LEFT JOIN on the AccountNo = ParentAccountNo, you can then filter out the rows where there were no matching ID's.
WITH Accounts AS(
SELECT *
FROM (VALUES (1,null,'ABC'),
(2,1,'ABCD'),
(3,1,'CDE'),
(4,2,'DEF'),
(5,null,'GHI'),
(6,3,'MNO'),
(7,5,'JKL')) V(AccountNo,ParentAccountNo,name))
SELECT t1.*
FROM Accounts t1
LEFT JOIN Accounts t2 ON t1.AccountNo = t2.ParentAccountNo
WHERE t2.AccountNo IS NULL
[DEMO HERE]
You were curious about the usage of WITH. . .
Here is an equivalent to my shorthand usage of WITH:
CREATE TABLE Accounts (
AccountNo INT NOT NULL,
ParentAccountNo INT NULL,
Name VARCHAR(200))
INSERT INTO Accounts
SELECT *
FROM (VALUES (1,null,'ABC'),
(2,1,'ABCD'),
(3,1,'CDE'),
(4,2,'DEF'),
(5,null,'GHI'),
(6,3,'MNO'),
(7,5,'JKL')) V(AccountNo,ParentAccountNo,name)
I want to make a UPDATE on tb_usermeta using one query, having meta_id, meta_key's and meta_value's. This is possible?
tb_usermeta:
+----+---------+-----------+------------+
| id | meta_id | meta_key | meta_value |
+----+---------+-----------+------------+
| 1 | 1 | user_nome | user 1 |
| 2 | 1 | user_fone | 99999 |
| 3 | 2 | user_nome | user 2 |
| 4 | 2 | user_fone | 88888 |
+----+---------+-----------+------------+
Ex: Data:
meta_id = 1, meta_key = user_nome, meta_value = user changed
meta_id = 1, meta_key = user_fone, meta_value = 696969
tb_usermeta after update:
+----+---------+-----------+-------------+
| id | meta_id | meta_key | meta_value |
+----+---------+-----------+-------------+
| 1 | 1 | user_nome | user changed|
| 2 | 1 | user_fone | 696969 |
| 3 | 2 | user_nome | user 2 |
| 4 | 2 | user_fone | 88888 |
+----+---------+-----------+-------------+
Consider the following...
DROP TABLE IF EXISTS eav;
CREATE TABLE eav
(entity INT NOT NULL
,attribute VARCHAR(12) NOT NULL
,value VARCHAR(20) NOT NULL
,PRIMARY KEY(entity,attribute)
);
INSERT INTO eav VALUES
(1,'user_nome','user 1'),
(1,'user_fone','99999'),
(2,'user_nome','user 2'),
(2,'user_fone','88888');
UPDATE eav
SET value = CASE attribute WHEN 'user_nome' THEN 'user changed'
WHEN 'user_fone' THEN '696969'
END
WHERE entity = 1;
SELECT * FROM eav;
+--------+-----------+--------------+
| entity | attribute | value |
+--------+-----------+--------------+
| 1 | user_nome | user changed |
| 1 | user_fone | 696969 |
| 2 | user_nome | user 2 |
| 2 | user_fone | 88888 |
+--------+-----------+--------------+
It would be nice to do this with a view - but I think MySQL would consider the fact that you're updating two things at once 'an update to multiple underlying tables', which is not allowed.
I would like to join two tables and select from two columns the first one if it is not null, of the other if the first is null. As an example imagine that we have the following tables:
names companies_to_names
-------------------------------- -----------------------------
|id_name | name | nickname | | id | id_name | id_company |
-------------------------------- -----------------------------
| 1 | NULL | manu | | 1 | 1 | 1 |
| 2 | Joe A. | NULL | | 2 | 2 | 1 |
| 3 | Bob B. | NULL | | 3 | 3 | 1 |
| 4 | NULL | alice | | 4 | 4 | 1 |
| 5 | NULL | other | | 5 | 5 | 2 |
-------------------------------- -----------------------------
And we want to show either the name, or the nickname of the guys who work for the company with id=1. Then, I want the following result:
--------------------
|id_name | username|
--------------------
| 1 | manu |
| 2 | Joe A. |
| 3 | Bob B. |
| 4 | alice |
--------------------
I was thinking in SELECT CASE WHEN, but I don't know how to do it. Something like:
SELECT NAMES.id_name CASE username
WHEN NAMES.name IS NULL THEN NAMES.nickname
WHEN NAMES.name IS NOT NULL THEN NAMES.name
END
FROM NAMES INNER JOIN COMPANIES_TO_NAMES ON NAMES.id_name = COMPANIES_TO_NAMES.id_name;
Am I right?
Here is a query that shows you how to solve your problem:
SELECT N.id_name
,IFNULL(N.name, N.nickname) AS [username]
,CASE
WHEN N.name IS NOT NULL THEN 'name'
ELSE 'nickname'
END AS [username_source]
FROM NAMES N
INNER JOIN companies_to_names C ON C.id_name = N.id_name
AND C.id = 1
Hope this will help you.
I can't wrap my head around a small (hopefully) MySQL question. I have a table called links. It contains a customer_id field and a linked_id field and basically links customer accounts to each other where customer_id is in the lead. The newly created accounts can spawn accounts themselves and I would like to see all accounts that were created by the logged on user + all the accounts created by subaccounts.
Table looks like this:
+----+-------------+-----------+
| id | customer_id | linked_id |
+----+-------------+-----------+
| 1 | 1 | 5 |
| 2 | 1 | 2 |
| 3 | 1 | 11 |
| 4 | 1 | 13 |
| 5 | 13 | 14 |
| 6 | 3 | 4 |
| 7 | 7 | 8 |
+----+-------------+-----------+
So if I am logged in as user with customer_id 1 then I would like to get the userlist with linked_id 5,2,11,13 (because they are a direct connection) and linked_id 14 (because this user was created by a user who is directly connected to 1).
The query needs to be a subquery to get all user details. I currently have:
SELECT username, firstname, lastname, email, active, level FROM customers WHERE id
IN (SELECT linked_id FROM links WHERE customer_id=1) or id=1;
This obviously only returns the direct connections and the user with id=1 directly.
Thanks to eggyal for putting me on the right track. Seeing the relative complexity I do not feel so ashamed anymore that I could not crack it in the first go.
I ended up doing some research and found some nice setups to used closure tables in mysql. I ended up creating a stored procedure to populate my closure table and of course the new table cust_closure. I renamed by links table to cust_links.
cust_links:
+-------------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| customer_id | int(11) | YES | | NULL | |
| linked_id | int(11) | YES | | NULL | |
+-------------+---------+------+-----+---------+----------------+
cust_closure:
+-------------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------+------+-----+---------+-------+
| customer_id | int(11) | YES | | NULL | |
| linked_id | int(11) | YES | | NULL | |
| distance | int(11) | YES | | NULL | |
+-------------+---------+------+-----+---------+-------+
And then added the stored procedure:
CREATE PROCEDURE populate_cust_closure()
BEGIN
DECLARE distance int;
TRUNCATE TABLE cust_closure;
SET distance = 0;
-- seed closure with self-pairs (distance 0)
INSERT INTO cust_closure (customer_id, linked_id, distance)
SELECT customer_id, customer_id, distance
FROM cust_links GROUP BY customer_id;
-- for each pair (root, leaf) in the closure,
-- add (root, leaf->child) from the base table
REPEAT
SET distance = distance + 1;
INSERT INTO cust_closure (customer_id, linked_id, distance)
SELECT cust_closure.customer_id, cust_links.linked_id, distance
FROM cust_closure, cust_links
WHERE cust_closure.linked_id = cust_links.customer_id
AND cust_closure.distance = distance - 1;
UNTIL ROW_COUNT()=0
END REPEAT;
END //
When I then called the stored procedure it produced:
mysql> select * from cust_closure;
+-------------+-----------+----------+
| customer_id | linked_id | distance |
+-------------+-----------+----------+
| 1 | 1 | 0 |
| 3 | 3 | 0 |
| 7 | 7 | 0 |
| 13 | 13 | 0 |
| 1 | 5 | 0 |
| 1 | 2 | 0 |
| 1 | 11 | 0 |
| 1 | 13 | 0 |
| 13 | 14 | 0 |
| 1 | 14 | 1 |
| 3 | 4 | 0 |
| 7 | 8 | 0 |
+-------------+-----------+----------+
So now my original query becomes:
SELECT username, firstname, lastname, email, active, level FROM customers WHERE id
IN (SELECT linked_id FROM cust_closure WHERE customer_id=1);
Thanks again for eggyal and hope this helps someone in the future.