Join query on Wordpress usermeta - mysql

We all love wordpress right?
So I've had to work with the usermeta table that basically have this structure.
umeta_id | user_id | meta_key | meta_value
For some reasons several in-house developer plugins wrote a lot of additional information on this table and lately I won the duty to work with it and pull out some important information that I need to export and save in a structure that actually make sense for a web application.
To provide an example this is the kind of data that I can find:
umeta_id | user_id | meta_key | meta_value
1 | 1 | ourID | asdad878d7a
2 | 1 | country | fooland
3 | 1 | firstname| foo
4 | 1 | lastname | bar
I would like to create a result that resemble this structure:
user_id | ourID | country
1 | asdad878d7a | fooland
I tried something but really this kind of structure isn't something I'm accustomed too.
This is my query so far:
SELECT meta.umeta_id as umeta_id, meta.user_id as user_id, channel.meta_value as ourID, country.meta_value as country
FROM usermeta as meta
INNER JOIN usermeta as channel
INNER JOIN usermeta as country
WHERE channel.meta_key = 'ourID'
AND country.meta_key = 'country'
But the result is basically something wrong. I'm having lots of duplicate of the same user_id, one for every row assigned to the user_id but only reporting the field selected instead of the value. Now while this make sense I don't know how to correctly write this query.
Something like this:
umeta_id | user_id | ourID | country
1 | 51424 | UC6Y94UM6rj | United Kingdom
1 | 51424 | UC6Y94UM6rj | Italy
1 | 51424 | UC6Y94UM6rj | Italy
1 | 51424 | UC6Y94UM6rj | Italy
1 | 51424 | UC6Y94UM6rj | Croatia
1 | 51424 | UC6Y94UM6rj | United States
1 | 51424 | UC6Y94UM6rj | Croatia
Clearly I'm doing something very wrong and I'm here hoping that someone can help me understand how to run this kind of query properly more than having the query done by someone else.

Would this get you closer to what you are looking for?
SELECT meta.umeta_id as umeta_id, meta.user_id as user_id, meta.meta_value as ourID, country.meta_value as country
FROM usermeta as meta
INNER JOIN usermeta as country ON meta.user_id = country.user_id
WHERE meta.meta_key = 'ourID'
AND country.meta_key = 'country'
The logic is to first find an entry that has meta_key 'ourID'. The value of user_id and ourID are picked up from this entry, so the inner join is only required to merge the value of country. The ON condition in INNER JOIN selects the correct country entry.

Related

Trying to find duplicates and who made them

I'm working on a legacy system that allowed the insertion of multiple entries with the same email. In the people table are present entries with same name and email and also different name with an already used email (es. the user didn't know or didn't ask the email address to the person and chose to put a fake one).
A person could subscribe to a User multiple times yearly basis
They asked me for a report of which users entered the most of these entries.
Let's say I have 3 tables
| people| | subscriptions| |users|
| ------| |--------------| |-----|
| id | | id | |id |
| name | | personId | |name |
| email | | userId |
| subYear |
I found all duplicate emails and their occurrences using this query
SELECT users.name, people.email, count(subscriptions.id) nSub
FROM people
INNER JOIN (SELECT email, count(id) occurrences
FROM people
where email is not null and email != ""
GROUP BY email
HAVING occurrences > 1) duplicates
ON people.email = duplicates.email
JOIN subscriptions ON people.id = subscriptions.personId
JOIN users on users.id = subscriptions.userId
group by users.name, people.email;
but now I'm stuck when I have to integrate users, the query gives incorrect results or gets stuck in a loop.
I'm sure I'm getting the grouping wrong but I got lost
The result I'm trying to achieve is something like (based on data provided in fiddle)
|users.name| people.email | occurrences |
|----------|-------------------------|-------------|
| User1 | example#example.com | 1 |
| User2 | example#example.com | 2 |
| User2 | fake#email.com | 3 |
| User3 | fake#email.com | 1 |
Any suggestion you can give me is welcome. Thank's in advance
UPDATE: Sorry for the sloppiness, I created a fiddle
sql-fiddle

join two tables in mysql and get records

I have two tables "contacts" and "users". Users table storing data with "," separated. Need to distinct data in "Contacts" column from "Contacts" table. And need to join with "Users" table, and get the records.
Contacts Table
--------------------------
id | user_Id | contats
--------------------------
1 | 2147483647 | 90123456789,90123456789,90123456789,90123456789
2 | 2147483647 | 90123456789,90123456789,90123456789,90123456789
3 | 919444894154 | 90123456789,90123456789,90123456789,90123456789
Users Table
-----------------------------
id | username | email | phone
-----------------------------
1 | bhavan | bhavanram93#gmail.com | 90123456789
2 | bhavan | bhavanram93#gmail.com | 90123456789
3 | prince | prince#gmail.com | 1234567980
4 | bhavan | bhavanram93#gmail.com | 90123456789
5 | hello | hello#gmail.com | 1234567890
6 | bhavan | bhavanram93#gmail.com | 90123456789
Your table Contacts shouldn't be constructed this way.
Since you want 1 Users table containing all the data about a user, and 1 Contacts table containing links between different users, you'd rather do this kind of table structure :
Contacts table
id | user_id | contact_id
-------------------------
1 | 1 | 2
2 | 1 | 3
3 | 2 | 3
That'll allow you to do something like :
SELECT *
FROM Users
JOIN Contacts ON (Users.id = Contacts.contact_id)
WHERE Contacts.user_id = 1
Which will return all the data of the contacts of the user 1.
Your current structure is a huge ongoing mess, it's the opposite of being flexible.
You should restructure your db to a normalized format as Steve suggest.
But if you cant:
SELECT *
FROM Users
JOIN Contacts
ON CONCAT(',', Contacts.contacts, ',') like
CONCAT('%,', Users.phone, ',%')
WHERE Contacts.user_id = 1
the idea is you convert your contacts to
, <numbers> ,
,90123456789,90123456789,90123456789,90123456789,
and try to match with
%,90123456789,%
Note this approach cant use any index so will have bad performance with many
rows. if you are in the order of 1k-10k rows may be ok. More than that you need consider restructure your db.

MYSQL (WHERE - IF - SELECT/IN statement)

I'm trying to set my code up where I have a Control Panel for my Sales Reps.
From my Control Panel, I am able to control which customers a Rep calls based on the item the customer bought.
i.e. If I assign "Cars" in my Control Panel for Sales Rep 01, he would only call customers that bought toys in the "Cars" category. And all different toys in my "Cars" category are stored in a separate file named "Vehicles".
My files are as follows:
customer (File)
+--------+-----------+--------+
| name | phone | toy |
+--------+-----------+--------+
| Gail | 777-1234 | Truck |
| June | 777-1235 | Doll |
| Mary | 777-1236 | Racer |
| Bill | 777-1237 | Ball |
| Jon | 777-1238 | Jeep |
+--------+-----------+--------+
control_panel (File)
+----------+--------+
| user | desc |
+----------+--------+
| sales_01 | Cars |
+----------+--------|
vehicles (File)
+---------+
+ item |
+---------+
| Truck |
| Racer |
| Jeep |
+---------+
In trying to test this code out, I have this portion of my code working.
select
c.name , c.phone
FROM
customer c
WHERE
c.toy IN (
SELECT
v.item
FROM
vehicles v
)
Now I'm trying to condition my WHERE statement so that only if I choose "Cars" in my Control Panel screen for User "sales_01", then customers who bought Cars will only show on the Call Screen for User "sales_01".
This is one example of some of the code I've been testing but cant get to work correctly.
SELECT
c.name , c.phone
FROM
customer c , control_panel p
WHERE
(IF p.desc = "Cars"
THEN (c.toy
IN (SELECT
v.item
FROM
vehicles v)
)
END)
Any help is appreciated. Thx.
To start with, I suggest you refactor your schema by adding an field category to your vehicles table. This will allow a proper relationship between your control_panel and customer. In that case you could just do SELECT c.name, c.phone FROM customer c LEFT OUTER JOIN vehicles v ON c.toy = v.items WHERE v.category = 'Cars'. I would have loved to add other suggestions but I feel you want something that could work right now. Plus, I do not have much time to spare presently. Hope this helps.

How to formulate query to show all courses taken by a person

I'm having trouble formulating a MySQL query correctly. Everything I've tried doesn't give me what's needed, or gives a syntax error.
I have three tables: Clients, Courses, and CoursesForClients.
The Clients table just has basic coordinates for a person: ID, Name, Address, email, etc.
+----------+-----------------------------+------+
| ClientID | Name | Address | etc. |
+----------+-----------------------------+------+
| 10 | Joe Smith | 1 Main St. | ... |
| 20 | Bob Smith | 2 Main St. | ... |
| ... | ... ... | ... ... ... | ... |
+----------+-----------------------------+------+
The Courses table stores the course name and its ID.
+----------+-----------------------+
| CourseID | Name |
+----------+-----------------------+
| 100 | Intro. to Subject |
| 200 | Intermediate Subject |
| 300 | Advanced Subject |
| ... | ... ... ... ... |
+----------+-----------------------+
The CoursesForClients table has the CourseID and ClientID. A given Client can have taken multiple courses, so for every course that a Client has taken, there's a row, with the person's ID and the Course ID.
+----------+----------+
| CourseID | ClientID |
+----------+----------+
| 100 | 1 |
| 200 | 1 |
| 300 | 1 |
| 100 | 2 |
| 200 | 2 |
| ... | ... |
+----------+----------+
Now, what I need is to be able to list the Client - just once - together with all the Courses she has taken. So, the result of the query might look like this:
10:Joe Smith
1 Main St.
Somewhere, AL
Intro. to Subject
Intermediate Subject
Advanced Subject
---------------------------
20:Bob Smith
2 Main St.
Somewhere, AL
Intro. to Subject
Intermediate Subject
So this output reflects the relationships between the Client and the Course. The key thing here is that, no matter how many Courses a Client has taken, the Client's particulars appear only once, followed by the list of all the courses she's taken.
There's an additional twist in that there's another table that lists the Grade for the Course for the Client, and that GradeID is also stored in the CoursesForClients table, and there's another table of Grades, with ID and Grade Description. But I won't worry about this right now. For now, all I want is just the basic output shown, as described above.
It looks like it should be easy to set up a query for this, with a JOIN and maybe a GROUP BY, but I'm having a block here and can't seem to get it right. So, any help will be hugely appreciated. Thank you!
SQL deals in tables. By definition a table has a bunch of rows, each of which has the same columns as each other. Your query is going to yield a result set that duplicates the client's information for each course she took.
Your presentation layer is going to format that table, by noticing the first row of each new client and breaking out the client header. You'll do that in php or Java or Crystal Reports or some such presentation tech.
Your query is something like this.
SELECT a.id, a.name, a.address, a.etc,
c.Name
FROM Clients a
JOIN CoursesForClients b USING(ClientID)
JOIN Courses c USING(CourseID)
ORDER BY a.id, c.CourseID
#Strawberry makes a good point about the pitfall of using USING(). Here is the same query on ON.
SELECT a.id, a.name, a.address, a.etc,
c.Name
FROM Clients a
JOIN CoursesForClients b ON a.ClientID = b.ClientID
JOIN Courses c ON b.CourseID = c.CourseID
ORDER BY a.id, c.CourseID

How to write a proper If...Else Statement with JOIN in MySQL?

I'm quite a beginner in MySQL I just know the totally basic statements, however now I'ts time for me to get into some more difficult, but worth stuff.
I actually have 3 tables in MySQL, here is the representation:
users:
user_id | name | country
---------------------------
1 | Joseph | US
2 | Kennedy | US
3 | Dale | UK
admins:
admin_id | name | country
----------------------------
1 | David | UK
2 | Ryan | US
3 | Paul | UK
notes:
id | n_id | note | comment | country | type | manager
----------------------------------------------------------------
1 | 3 | This is the 1st note | First | US | admin | 2
2 | 2 | This is the 2nd note | Second | US | user | 1
3 | 2 | This is the 3rd note | Third | UK | user | 2
Now I would like to execute something like this SQL (I'm going to type not real commands here, because I'm not really familiar with all of the SQL expressions):
IF notes.type = admin
THEN
SELECT
notes.note,
notes.comment,
notes.country,
admins.name,
admins.country
FROM notes, admins
WHERE notes.n_id = admin.admin_id
ELSEIF notes.type = 'user'
SELECT
notes.note,
notes.comment,
notes.country,
users.name,
users.country
FROM notes, users
WHERE notes.n_id = users.user_id
I hope you understand what would I like to achieve here. I could do this easily with more SQL statements, but I would like to try some query which doesn't use that much resources.
Edit 1:
I would like to Get all of the Notes and get which usergroup has submitted it than apply the user's name to it. I mean, if the admin submitted the note, than SQL should choose the ID from the Admin table (as per the type value) but if a User submitted the note, it should get the name from the Users table.
The result should look something similar to this:
result:
------
id | note | comment | country | name
--------------------------------------------------------
1 | This is the 1st note | First | US | Paul
2 | This is the 2nd note | Second | US | Kennedy
3 | This is the 3rd note | Third | UK | Kennedy
Edit 2:
I have actually forgot to mention, that all of these should be listed to a manager. So a 'manager ID' should be added to the Notes and list all of the notes where the manager is for example: 2.
Here is a method that you can do in one query:
SELECT n.note, n.comment, n.country,
coalesce(a.name, u.name) as name, coalesce(a.country, u.country) as country
FROM notes n left join
admins a
on n.n_id = a.admin_id and n.type = 'admin' left join
users u
on n.n_id = u.user_id and n.type = 'user';
This uses left join to bring the records together from both tables. It then chooses the matching record for the select.
To select a particular manager, remove the semicolon and add:
where n.manager = 2;
If you expect admins and users in one result you have got several options. The simplest way is to make a union select like this:
SELECT
notes.note,
notes.comment,
notes.country,
admins.name,
admins.country
FROM
notes join admins on notes.n_id = admin.admin_id
WHERE
notes.manager = 2
UNION ALL
SELECT
notes.note,
notes.comment,
notes.country,
users.name,
users.country
FROM
notes join users on notes.n_id = users.user_id
WHERE
notes.manager = 2