Adding a query (new join) to an existing join - mysql

So I have three databases (all on one server) that I need to join tables on. Essentially I do a join across two tables to determine the identification of particular users who do a certain thing after a certain date. It works fine:
SELECT a.THING, a.ANOTHERTHING, b.IDENTIFICATION, b.RELEVANTDATE
FROM FIRSTDATABASE.TABLE a
JOIN SECONDDATABASE.TABLE b
ON a.THING = b.THING
WHERE ANOTHERTHING = '----' AND IDENTIFICATION <> 'NULL'
AND b.RELEVANTDATE > date('YYYY-MM-DD')
At present I'm also running a second query by its lonesome - this is one table, on a third database - to get all users with a certain amount of an item. It also works:
SELECT ITEM, AMOUNT, IDENTIFICATION
FROM TABLE
WHERE ITEM = '----' AND AMOUNT > '0' AND IDENTIFICATION <> 'NULL'
GROUP BY AMOUNT
I then, using the first table as my guide, use VLOOKUP so I can get the AMOUNT generated in the second query for each and every user IDENTIFICATION meeting the criteria after a certain date AND who did a certain thing, from the first query.
My question is, how would I join these two into one large query?

Related

Comparing each colum in a row to every row in the database sql

I am building a bot that matches users based on a score they get, this score is taken from calculations done to data in a database on the request of the user.
I have only 1 table in that database and a few columns (user,age,genre,language,format,...etc).
What I want to do is, once the user clicks "find match" button on the chatbot, this user's data, which is already in the database will be compared to the other user's data in the same table and compare each column 1 by 1 of each row.
For example, the user's genre preference will be compared to each genre pref of the other users in each row of the table, when there is a match, 1 point is added, then language will be compared of each user and 1 point is given when there's a match. This will go to each column in each row and be compared with the user's. In the end, the users that has highest matching points will be recommended to this user.
What's the best way and approach to do that?
I am using nodejs and mysql database.
Thank you.
I see this as a self join and conditional expressions:
select t.*,
(t1.genre = t.genre) + (t1.language = t.language) + (t1.format = t.format) as score
from mytable t
inner join mytable t1 on t1.user <> t.user
where t1.user = ?
order by score desc
The question mark represents the id of the currently logged on user, for who you want to search matching users. The query brings all other users, and counts how many values they have in common over the table columns: each matching value increases the score by 1. Results are sorted by descending score.

mysql query using column values as parameter in query phpMyAdmin

I have a query i have been working on trying to get a specific set of data, join the comments in duplicate phone numbers of said data, then join separate tables based on a common field "entry_id" which also happens to be the number on the end of the word custom_ to pull up that table.
table named list and tables containing the values i want to join is custom_entry_id (with entry_id being a field in list in which i need the values of each record to replace the words in order to pull up that specific table) i need entry_id from the beginning part of my query to stick onto the end of the word custom for every value my search returns to get the fields from that custom table designated for that record. so it will have to do some sort of loop i guess? sorry like i said I am at a loss at this point
this is where i am so far:
SELECT * ,
group_concat(comments SEPARATOR '\r\n\r\n') AS comments_combined
FROM list WHERE `status` IN ("SALEA","SALE")
GROUP BY phone_number
//entry_id is included in the * as well as status
// group concat combines the comments if numbers are same
i have also experimented on test data with doing a full outer join which doesnt really exist. i feel if you can solve the other part for me i can do the joining of the data with a query similar to this.
SELECT * FROM test
LEFT JOIN custom_sally ON test.num = custom_sally.num
UNION
SELECT * FROM test
RIGHT JOIN custom_sally ON test.num = custom_sally.num
i would like all of this to appear with every field from my list table in addition to all the fields in the custom_'entry_id' tables for each specific record. I am ok with values being null for records that have different custom fields. so if record 1 has custom fields after the join of hats and trousers and record 2 has socks and shoes i realize that socks and shoes for record 1 will be null and hats and trousers for record 2 will be null.
i am doing all this in phpmyadmin under the SQL tab.
if that is a mistake please advise as well. i am using it because ive only been working with SQl for a few months. from what i read its the rookie tool.
i might be going about this all wrong if so please advise
an example
i query list with my query i get 20,000 rows with columns like status, phone_number, comments, entry_id, name, address, so on.
now i want to join this query with custom fields in another table.
the problem is the custom tables' names are all linked to the entry_id.
so if entry_id is 777 then the custom table fields are custom_777
my database has over 100 custom tables with specials fields for each record depending on its entry_id.
when i query the records I don't know how to join the custom fields that are entry_id specific to the rest of my data.i will pull up some tables and data for a better example
this is the list table:
this is the custom_"entry_id"
Full Outer Join in MySQL
for info on full outer joins.

Can mysql join occur on different data types

Suppose we have two tables, table A (parent) and table B (children) with a one to many relationship between them, established via parent_id (VARCHAR (100)) field in table B.
The parent_id field's datatype is different from id (INT(11)) field in table A. So the question is can MYSQL JOIN query return the proper records?
I encountered this kind of situation. I am running the following query:
SELECT p.payment_amount, s.company_name
FROM payments p
LEFT JOIN suppliers s ON p.supplier_id = s.id
LIMIT 5
Here one supplier has multiple payments. Now this query is returning me 5 records in which I can see the payment_amount for all 5 records but I can see company_name for only those records which have p.supplier_id one digit length. If in database I modify p.supplier_id to any valid 2 digit id, I cant get the supplier record.
MySQL can join with different data type, but the performance is poor as it has to convert from one type to the other for each row.
I set up a quick SQL fiddle to demonstrate it working, based on your SQL above:-
http://www.sqlfiddle.com/#!2/f7d02a/1
Note that a leading character in the number stored in a string will result in it being evaluated to 0.

JOINing tables while ignoring duplicates

So, let's say I have a hash/relational table that connects users, teams a user can join, and challenges in which teams participate (teams_users_challenges), as well as a table that stores entered data for all users in a given challenge (entry_data). I want to get the average scores for each user in the challenge (the average value per day in a given week). However, there is a chance that a user will somehow join more than one team erroneously (which shouldn't happen, but does on occasion). Here is the SQL query below that gets a particular user's score:
SELECT tuc.user_id, SUM(ed.data_value) / 7 as value
FROM teams_users_challenges tuc
LEFT JOIN entry_data ed ON (
tuc.user_id = ed.user_id AND
ed.entry_date BETWEEN '2013-09-16' AND '2013-09-22'
)
WHERE tuc.challenge_id = ___
AND tuc.user_id = ___
If a user has mistakenly joined more than one team, (s)he would have more than one entry in teams_users_challenges, which would essentially duplicate the data retrieved. So if a user is on 3 different teams for the same challenge, (s)he would have 3 entries in teams_users_challenges, which would multiply their average value by 3, thanks to the LEFT JOIN that automatically takes in all records, and not just one.
I've tried using GROUP BY, but that doesn't seem to restrict the data to only one instances within teams_users_challenges. Does anybody have any ideas as to how I could restrict the query to only take in one record within teams_users_challenges?
ADDENDUM: The columns within teams_users_challenges are team_id, user_id, and challenge_id.
If this is a new empty table, you can express your 'business rule' that a user should only join one team per challenge as a unique constraint in SQL:
alter table teams_users_challenges
add constraint oneUserPerTeamPerChallenge
unique (
user_id
, team_id
, challenge_id
);
If you can't change the table, you'll need to group by user and team and pick a single challenge from each group in the query result. Maybe pick just the latest challenge.
I can't test it, but if you can't clean up the data as Yawar suggested, try:
SELECT tuc.user_id, SUM(ed.data_value) / 7 as value
FROM entry_data ed
LEFT JOIN
(
select tuc.user_id, tuc.challenge_id from teams_users_challenges tuc group by tuc.user_id, tuc.challenge_id
) AS SINGLE_TEAM
ON SINGLE_TEAM.user_id = ed.user_id AND
ed.entry_date BETWEEN '2013-09-16' AND '2013-09-22'
WHERE tuc.challenge_id = ___
AND tuc.user_id = ___

How do I select a record from one table in a mySQL database, based on the existence of data in a second?

Please forgive my ignorance here. SQL is decidedly one of the biggest "gaps" in my education that I'm working on correcting, come October. Here's the scenario:
I have two tables in a DB that I need to access certain data from. One is users, and the other is conversation_log. The basic structure is outlined below:
users:
id (INT)
name (TXT)
conversation_log
userid (INT) // same value as id in users - actually the only field in this table I want to check
input (TXT)
response (TXT)
(note that I'm only listing the structure for the fields that are {or could be} relevant to the current challenge)
What I want to do is return a list of names from the users table that have at least one record in the conversation_log table. Currently, I'm doing this with two separate SQL statements, with the one that checks for records in conversation_log being called hundreds, if not thousands of times, once for each userid, just to see if records exist for that id.
Currently, the two SQL statements are as follows:
select id from users where 1; (gets the list of userid values for the next query)
select id from conversation_log where userid = $userId limit 1; (checks for existing records)
Right now I have 4,000+ users listed in the users table. I'm sure that you can imagine just how long this method takes. I know there's an easier, more efficient way to do this, but being self-taught, this is something that I have yet to learn. Any help would be greatly appreciated.
You have to do what is called a 'Join'. This, um, joins the rows of two tables together based on values they have in common.
See if this makes sense to you:
SELECT DISTINCT users.name
FROM users JOIN conversation_log ON users.id = converation_log.userid
Now JOIN by itself is an "inner join", which means that it will only return rows that both tables have in common. In other words, if a specific conversation_log.userid doesn't exist, it won't return any part of the row, user or conversation log, for that userid.
Also, +1 for having a clearly worded question : )
EDIT: I added a "DISTINCT", which means to filter out all of the duplicates. If a user appeared in more than one conversation_log row, and you didn't have DISTINCT, you would get the user's name more than once. This is because JOIN does a cartesian product, or does every possible combination of rows from each table that match your JOIN ON criteria.
Something like this:
SELECT *
FROM users
WHERE EXISTS (
SELECT *
FROM conversation_log
WHERE users.id = conversation_log.userid
)
In plain English: select every row from users, such that there is at least one row from conversation_log with the matching userid.
What you need to read is JOIN syntax.
SELECT count(*), users.name
FROM users left join conversion_log on users.id = conversation_log.userid
Group by users.name
You could add at the end if you wanted
HAVING count(*) > 0