Mysql select on non linked tables - mysql

I've got two tables, that are not linked the standard way (I'm aware this isn't a good way to do it)
lets say the tables are setup like the below
Table:
component
fields:
cid, cname, rangeid, company
Table: ranges
fields:
rid, rangename, year
While this is quite simple in a relational DB, i'm not too sure of the cleanest way to do this otherwise (remaking the DB is not an option).
the basic query I need is.
select * from component where range.year = '2014' and company = 'xxx'
any advice would be greatly appreciated.

Is this what you're looking for?
SELECT a.cid, a.cname, a.rangeid, a.company, b.rid, b.rangename, b.year
FROM component a
JOIN ranges b ON
b.rid = a.rangeid
WHERE b.year = 2014
AND a.company = 'xxx'
Result
| CID | CNAME | RANGEID | COMPANY | RID | RANGENAME | YEAR |
------|-----------|---------|---------|-----|-----------|------|
| 1 | Component | 1 | xxx | 1 | Range | 2014 |
Demo
If a range from component may not exist in ranges, then use a LEFT JOIN.

JOIN the two tables:
select c.cname, r.rangename, r.year, ...
from component AS c
INNER JOIN ranges AS r ON c.rangeid = r.rid
where r.year = '2014'
and c.company = 'xxx';
Note that: You can JOIN any tables normally, even if they haven't any relation between them, just put the condition in the ON clause, just like in your case. But, you have to ensure that indexes are setup correctly, see this page fore more information:
Multiple-Column Indexes

JOIN is what you are looking for :
select *
from component
inner join ranges on rid = rangeid and year = 2014
where company = 'xxx'

Related

SELECT using three tables w/ 1000+ entries

For transaction listing I need to provide the following columns:
log_out.timestamp
items.description
log_out.qty
category.name
storage.name
log_out.dnr ( Representing the users id )
Table structure from log_out looks like this:
| id | timestamp | storageid | itemid | qty | categoryid | dnr |
| | | | | | | |
| 1 | ........ | 2 | 23 | 3 | 999 | 123 |
As one could guess, I only store the corresponding ID's from other tables in this table. Note: log_out.id is the primary key in this table.
To get the the corresponding strings, int's or whatever back, I tried two queries.
Approach 1
SELECT i.description, c.name, s.name as sname, l.*
FROM items i, categories c, storages s, log_out l
WHERE l.itemid = i.id AND l.storageid = s.id AND l.categoryid = c.id
ORDER BY l.id DESC
Approach 2
SELECT log_out.id, items.description, storages.name, categories.name AS cat, timestamp, dnr, qty
FROM log_out
INNER JOIN items ON log_out.itemid = items.id
INNER JOIN storages ON log_out.storageid = storages.id
INNER JOIN categories ON log_out.categoryid = categories.id
ORDER BY log_out.id DESC
They both work fine on my developing machine, which has approx 99 dummy transactions stored in log_out. The DB on the main server got something like 1100+ tx stored in the table. And that's where trouble begins. No matter which of these two approaches I run on the main machine, it always returns 0 rows w/o any error *sigh*.
First I thought, it's because the main machine uses MariaDB instead of MySQL. But after I imported the remote's log_out table to my dev-machine, it does the same as the main machine -> return 0 rows w/o error.
You guys got any idea what's going on ?
If the table has the data then it probably has something to do with JOIN and related records in corresponding tables. I would start with log_out table and incrementally add the other tables in the JOIN, e.g.:
SELECT *
FROM log_out;
SELECT *
FROM log_out
INNER JOIN items ON log_out.itemid = items.id;
SELECT *
FROM log_out
INNER JOIN items ON log_out.itemid = items.id
INNER JOIN storages ON log_out.storageid = storages.id;
SELECT *
FROM log_out
INNER JOIN items ON log_out.itemid = items.id
INNER JOIN storages ON log_out.storageid = storages.id
INNER JOIN categories ON log_out.categoryid = categories.id;
I would execute all the queries one by one and see which one results in 0 records. Additional join in that query would be the one with data discrepancy.
You're queries look fine to me, which makes me think that it is probably something unexpected with the data. Most likely the ids in your joins are not maintained right (do all of them have a foreign key constraint?). I would dig around the data, like SELECT COUNT(*) FROM items WHERE id IN (SELECT itemid FROM log_out), etc, and seeing if the returns make sense. Sorry I can't offer more advise, but I would be interested in hearing if the problem is in the data itself.

MySQL - return single record by joining multiple tables with multiple WHERE/OR clauses

Did many searches and were able to write all the JOIN queries except this one. I have 3 tables, which look like:
TABLE - accounts
account_id | account_email
1 | aa#bb.com
2 | cc#dd.com
TABLE - products
product_id | product_name
1 | name1
2 | name2
TABLE - licenses
license_id | account_id | product_id | license_code
1 | 1 | 1 |
2 | 1 | 2 |
3 | 0 | 1 | abc123
I know account_email, product_id and license_code (this one can be empty) variables, and need to check if client has license for selected product (searching by account_email or license_code).
The problem is that account_id sometimes can be 0 (in other words, client has license, but client's profile is not stored in the accounts table).
Trying to use this one, but it returns wrong (duplicated) results:
SELECT * FROM licenses
INNER JOIN products ON licenses.product_id=products.product_id AND products.product_id='X'
INNER JOIN accounts ON licenses.account_id=accounts.account_id AND accounts.account_email='XYZ' OR licenses.license_code='ZZZ'
The question: how do I rewrite query, so I can find a record by account_email or license_code field? Put simply, if account_id is not 0 (profile exists), I should see data from 3 tables (accounts, products, licenses). If account_id is 0, I should see data from 2 tables (values from accounts table should be displayed as empty/null).
Needless to say, account_email and license_code fields are unique.
You just need to adjust the parentheses. However, I would use a separate WHERE clause:
SELECT *
FROM licenses l INNER JOIN
products p
ON l.product_id = p.product_id INNER JOIN
accounts a
ON l.account_id = a.account_id
WHERE p.product_id = 'X' AND
(a.account_email='XYZ' OR l.license_code = 'ZZZ')
You can keep the filters in the ON clauses -- there is nothing wrong with that. I just prefer to separate join conditions from filtering conditions. The important part are the parentheses, so the ON clause is not interpreted as:
ON (l.account_id = a.account_id AND a.account_email = 'XYZ') OR
licenses.license_code = 'ZZZ'
This is the interpretation without parens.
After some more code modification and testing, here's the code which works perfectly. It's a modified Gordon Linoff's code (original code didn't work when only license_code was known, and email address wasn't known). So most of credits go to Gordon Linoff for his efforts.
SELECT *
FROM licenses l JOIN
products p
ON l.product_id = p.product_id LEFT JOIN
accounts a
ON l.account_id = a.account_id
WHERE p.product_id = 'X' AND
(a.account_email='XYZ' OR l.license_code = 'ZZZ')

MYSQL 4 Table Query

I could use some expert advice with a MYSQL query I'm trying to put together.
What i would like to do:
I'm trying to create a page that will allow users to perform an advanced search across multiple tables.
The 4 tables are:
members, profiles, skills, genre
Members:
*********************************
id | member_id | login | zipcode
*********************************
Profiles:
*********************************************************************
id | member_id | exp | commitment | practice | gigs | availability
*********************************************************************
Skills:
************************************************************************
id | member_id | lead_vocals | background_vocals | guitar | bass| drums
************************************************************************
Genre:
********************************************************************************
id | member_id | alternative | classic_rock | modern_rock | blues | heavy_metal
********************************************************************************
Skills and Genre represent check box values checked or not (1 or 0)
The search form would be a series of checkboxes and dropdowns that would allow a user to specify the specific items they want to search for.
What I need help with:
I need help coming up with the best way to put this query together. I've been reading up on Joins, Unions, Sub Queries and Derived tables. I can do some basic queries and get part of the data for example:
SELECT members.member_id FROM members LEFT JOIN skills ON members.member_id = skills.member_id WHERE skills.leadvocals = 1
However I just cant seem to wrap my head around putting it all together.
An example of the search criteria would look something like this:
A user fills out the form and wants to search for all members with (members table) zipcode = 11111 OR zipcode = 22222 (profiles table) commitment = ANY, practice = ANY, gigs = 1, availability = ANY (skills table) lead_vocals = 1 and lead_guitar = 1 (genre table) alternative = 1, modern_rock = 1, heavy_metal = 1
Note I already have the logic to calculate the zipcode distance and return a list of zip codes in the range.
At the end of the day the query just needs to return a list of results with member_id and login from the members table that match the criteria.
I'm not looking for somebody to just provide that answer (although I wouldn't mind the answer :)) I learn better by trying to figure it out on my own but I need some help getting started.
Thanks in advance.
The SQL query in the question seems valid, you just need to add the rest of the tables and conditions to get the data you want.
A user fills out the form and wants to search for all members with
(members table) zipcode = 11111 OR zipcode = 22222 (profiles table)
commitment = ANY, practice = ANY, gigs = 1, availability = ANY
(skills table) lead_vocals = 1 and lead_guitar = 1 (genre table)
alternative = 1, modern_rock = 1, heavy_metal = 1
You already put half of the query in your request, except it is written in English and it happens that SQL is just a small subset of English.
The tables you mentioned appear in the FROM clause:
FROM members m
INNER JOIN profiles p USING (member_id)
INNER JOIN skills s USING (member_id)
INNER JOIN genre g USING (member_id)
The conditions appear in the WHERE clause:
WHERE p.gigs = 1
AND s.lead_vocals = 1 AND s.guitar = 1
AND g.alternative = 1 AND g.modern_rock = 1 AND g.heavy_metal = 1
The fields that allow ANY value do not appear in the query, they do not filter the results.
Searching more than one value for zipcode can be done using the IN operator:
AND m.zipcode IN ('11111', '22222')
At the end of the day the query just needs to return a list of results with member_id and login from the members table that match the criteria.
The fields to be returned goes to the SELECT clause:
SELECT m.member_id, m.login
Maybe you want to get the list of members in a specific order, for example sorted by their login names:
ORDER BY m.login
... or by some of their skills; put lead vocals in front of the list:
ORDER BY s.lead_vocals DESC
(order DESCending to get those having 1 in front of those having 0 in column lead_vocals
Now, if we put all together we get the complete query:
SELECT m.member_id, m.login
FROM members m
INNER JOIN profiles p USING (member_id)
INNER JOIN skills s USING (member_id)
INNER JOIN genre g USING (member_id)
WHERE p.gigs = 1
AND s.lead_vocals = 1 AND s.lead_guitar = 1
AND g.alternative = 1 AND g.modern_rock = 1 AND g.heavy_metal = 1
AND m.zipcode IN ('11111', '22222')
ORDER BY s.lead_vocals DESC, m.login
Because you get the information from user input you don't know in advance that practice, for example, is allowed to have ANY value. You need to compose the query from pieces, using the data received from the form.
try this query.
select
m.*
from
members m
left join Profiles p on p.member_id = m.id
left join Skills s on s.member_id = m.id
left join Genre g on g.member_id = m.id
where (m.zipcode = 11111 OR m.zipcode = 22222) and p.gigs = 1 and s.lead_vocals = 1 and s.lead_guitar = 1 and g.alternative = 1, g.modern_rock = 1, g.heavy_metal = 1

MySQL select row with two matching joined rows from another table

Hey I try to select a row from a table with two matching entries on another one.
The structure is as following:
----------------- ---------------------
| messagegroups | | user_messagegroup |
| | | |
| - id | | - id |
| - status | | - user_id |
| | | - messagegroup_id |
----------------- | |
---------------------
There exist two rows in user_messagegroup with the ids of two users and both times the same messagegroup_id.
I would like to select the messagegroup where this two users are inside.
I dont get it.. so I would appreciate some help ;)
The specification you provide isn't very clear.
You say "with the ids of two users"... if we take that to mean you have two user_id values you want to supply in the query, then one way to to find the messagegroups that contain these two specific users:
SELECT g.id
, g.status
FROM messagegroups g
JOIN ( SELECT u.messagegroup_id
FROM user_messagegroup u
WHERE u.user_id IN (42, 11)
GROUP BY u.messagegroup_id
HAVING COUNT(DISTINCT u.user_id) = 2
) c
ON c.messagegroup_id = g.id
The returned messagegroups could also contain other users, besides the two that were specified.
If you want to return messagegroups that contain ONLY these two users, and no other users...
SELECT g.id
, g.status
FROM messagegroups g
JOIN ( SELECT u.messagegroup_id
FROM user_messagegroup u
WHERE u.user_id IS NOT NULL
GROUP BY u.messagegroup_id
HAVING COUNT(DISTINCT IF(u.user_id IN (42,11),u.user_id,NULL)) = 2
AND COUNT(DISTINCT u.user_id) = 2
) c
ON c.messagegroup_id = g.id
For improved performance, you'll want suitable indexes on the tables, and it may be possible to rewrite these to eliminate the inline view.
Also, if you only need the messagegroup_id value, you could get that from just the inline view query, without the need for the outer query and the join operation to the messagegroups table.

MySQL - select 3 tables with correct left join syntax

Hope you can help me with correct syntax of a SQL query (using MySQL 5.5.25).
I have 3 tables:
data
data_tmp
users
data table is empty - has it's own structure but no rows
data:
id | name | who
----------------
data_tmp:
id | cars | who
---------------
1 | lambo| 2
users
who | name |
------------
2 | john
My query is:
SELECT DISTINCT
users.name,
(SELECT count(id) FROM data WHERE who = 1) as number,
data_tmp.cars
FROM
users, data, data_tmp
WHERE
users.who = 2
AND data_tmp.who = 2
AND data.who = 2
This of course returns an empty result (there is no row that suits to all parameters because data is empty).
What I would like to achieve is:
users.name | number | data_tmp.cars |
-------------------------------------
john | 0 | lambo |
I am sure I have to - in some way - use LEFT JOIN but can't find correct syntax. Hope you can help me.
Kalreg
give this a try (without using subquery)
SELECT a.name, b.cars, count(c.id) as number
FROM users a
INNER JOIN data_tmp b
on a.who = b.who
LEFT JOIN data c
on a.who = c.who AND
a.name = c.name
WHERE a.who = 2
GROUP BY a.name, b.cars
this works on different servers:
MSSQL SERVER # SQLFIDDLE
MYSQL # SQLFIDDLE
Your assumption is right: you have to use left JOIN, in this way :
SELECT DISTINCT users.name, (SELECT count(id) FROM data WHERE who = 1) as number, data_tmp.cars
FROM users
JOIN data_tmp USING (who)
LEFT JOIN data USING(who)
WHERE users.who = 2