MySQL multiple select with different wheres in single query - mysql

First of, at the moment I am forced to use MySQL despite it being deprecated. I am very well aware of that fact. Hopefully you guys can still help me with my sql syntax.
I am trying to access several columns from some different tables. Problem is, some of the columns require a different where clause than the last column I need, and the where clause for the last column requires info from the rest of the query so I cannot split it up into multiple queries, I've tried.
I cannot use union because one select statement selects four columns, and the other one selects one column.
Query:
(SELECT DISTINCT inventory.Quantity, itemtypes.Itemtypename,
itemtypes.ItemtypeID, inventory.ItemID
FROM inventory JOIN itemtypes ON inventory.ItemtypeID = itemtypes.ItemtypeID
JOIN sets ON inventory.SetID = sets.SetID
WHERE inventory.ItemtypeID = itemtypes.ItemtypeID
AND itemtypes.Itemtypename = 'Set'
AND sets.SetID = '".$setid."')
UNION
(SELECT DISTINCT sets.Setname
FROM sets JOIN inventory ON sets.SetID = inventory.ItemID
WHERE sets.SetID = inventory.ItemID)
This is what I tried to use, with no success. I cannot seem to find any other way of linking to different select statements without using multiple queries (with due to the structure of my PHP file, is impossible to do properly). The rest of the file will work, if only this problem gets solved. Hopefully you guys can help me with this, please let me know if this is even possible to do. Let me know if you need to see my PHP code as well. $setid is derived from a get in the file and contains a value existing in the database.

May be, you can try like this. It works fine in SQL Server.
SELECT TMP1.Quantity,TMP1.Itemtypename, TMP1.ItemtypeID, TMP1.ItemID, TMP2.Setname
FROM(
SELECT DISTINCT
inventory.Quantity,
itemtypes.Itemtypename,
itemtypes.ItemtypeID,
inventory.ItemID
FROM inventory
JOIN itemtypes ON inventory.ItemtypeID = itemtypes.ItemtypeID
JOIN sets ON inventory.SetID = sets.SetID
WHERE inventory.ItemtypeID = itemtypes.ItemtypeID
AND itemtypes.Itemtypename = 'Set'
AND sets.SetID = '".$setid."'
) AS TMP1,
(
SELECT DISTINCT
sets.Setname
FROM sets
JOIN inventory ON sets.SetID = inventory.ItemID
WHERE sets.SetID = inventory.ItemID
) AS TMP2
Hope this is what you want. Your question seems very ambiguous.

Related

Complex MySQL query problems and also SQL hangs

I am trying to write an SQL query which is pretty complex. The requirements are as follows:
I need to return these fields from the query:
track.artist
track.title
track.seconds
track.track_id
track.relative_file
album.image_file
album.album
album.album_id
track.track_number
I can select a random track with the following query:
select
track.artist, track.title, track.seconds, track.track_id,
track.relative_file, album.image_file, album.album,
album.album_id, track.track_number
FROM
track, album
WHERE
album.album_id = track.album_id
ORDER BY RAND() limit 10;
Here is where I am having trouble though. I also have a table called "trackfilters1" thru "trackfilters10" Each row has an auto incrementing ID field. Therefore, row 10 is data for album_id 10. These fields are populated with 1's and 0's. For example, album #10 has 10 tracks, then trackfilters1.flags will contain "1111111111" if all tracks are to be included in the search. If track 10 was to be excluded, then it would contain "1111111110"
My problem is including this clause.
The latest query I have come up with is the following:
select
track.artist, track.title, track.seconds,
track.track_id, track.relative_file, album.image_file,
album.album, album.album_id, track.track_number
FROM
track, album, trackfilters1, trackfilters2
WHERE
album.album_id = track.album_id
AND
( (album.album_id = trackfilters1.id)
OR
(album.album_id=trackfilters2.id) )
AND
( (mid(trackfilters1.flags, track.track_number,1) = 1)
OR
( mid(trackfilters2.flags, track.track_number,1) = 1))
ORDER BY RAND() limit 2;
however this is causing SQL to hang. I'm presuming that I'm doing something wrong. Does anybody know what it is? I would be open to suggestions if there is an easier way to achieve my end result, I am not set on repairing my broken query if there is a better way to accomplish this.
Additionally, in my trials, I have noticed when I had a working query and added say, trackfilters2 to the FROM clause without using it anywhere in the query, it would hang as well. This makes me wonder. Is this correct behavior? I would think adding to the FROM list without making use of the data would just make the server procure more data, I wouldn't have expected it to hang.
There's not enough information here to determine what's causing the performance issue.
But here's a few suggestions and comments.
Ditch the old-school comma syntax for the join operations, and use the JOIN keyword instead. And relocate the join predicates to an ON clause.
And for heaven's sake, format the SQL so that it's decipherable by someone trying to read it.
There's some questions here... will there always be a matching row in both trackfilters1 and trackfilters2 for rows you want to return? Or could a row be missing from trackfilters2, and you still want to return the row if there's a matching row in trackfilters1? (The answer to that question determines whether you'd want to use an outer join vs an inner join to those tables.)
For best performance with large sets, having appropriate indexes defined is going to be critical.
Use EXPLAIN to see the execution plan.
I suggest you try writing your query like this:
SELECT track.artist
, track.title
, track.seconds
, track.track_id
, track.relative_file
, album.image_file
, album.album
, album.album_id
, track.track_number
FROM track
JOIN album
ON album.album_id = track.album_id
LEFT
JOIN trackfilters1
ON trackfilters1.id = album.album_id
LEFT
JOIN trackfilters2
ON trackfilters2.id = album.album_id
WHERE MID(trackfilters1.flags, track.track_number, 1) = '1'
OR MID(trackfilters2.flags, track.track_number, 1) = '1'
ORDER BY RAND()
LIMIT 2
And if you want help with performance, provide the output from EXPLAIN, and what indexes are defined.

SQL query to select based on many-to-many relationship

This is really a two-part question, but in order not to mix things up, I'll divide into two actual questions. This one is about creating the correct SQL statement for selecting a row based on values in a many-to-many related table:
Now, the question is: what is the absolute simplest way of getting all resources where e.g metadata.category = subject AND where that category's corresponding metadata.value ='introduction'?
I'm sure this could be done in a lot of different ways, but I'm a novice in SQL, so please provide the simplest way possible... (If you could describe briefly what the statement means in plain English that would be great too. I have looked at introductions to SQL, but none of those I have found (for beginners) go into these many-to-many selections.)
The easiest way is to use the EXISTS clause. I'm more familiar with MSSQL but this should be close
SELECT *
FROM resources r
WHERE EXISTS (
SELECT *
FROM metadata_resources mr
INNER JOIN metadata m ON (mr.metadata_id = m.id)
WHERE mr.resource_id = r.id AND m.category = 'subject' AND m.value = 'introduction'
)
Translated into english it's 'return me all records where this subquery returns one or more rows, without returning the data for those rows'. This sub query is correlated to the outer query by the predicate mr.resource_id = r.id which uses the outer row as the predicate value.
I'm sure you can google around for more examples of the EXIST statement

How can I modify this query with two Inner Joins so that it stops giving duplicate results?

EDIT: I will leave the post here as is, but what I really needed to accomplish needed to be reposted. I didn't explain the problem well enough. After trying again with quite a different starting point, I was able to get the query that I needed. That is explained here.
ORIGINAL QUESTION:
I'm having trouble. I have looked at similar threads, and I am unable to find a solution specific to this query. The database is very large, and group by seems to slow it down immensely.
The problem is I am getting duplicate results. Here is my query which causes duplicates:
SELECT
itpitems.identifier,
itpitems.name,
itpitems.subtitle,
itpitems.description,
itpitems.itemimg,
itpitems.mainprice,
itpitems.upc,
itpitems.isbn,
itpitems.weight,
itpitems.pages,
itpitems.publisher,
itpitems.medium_abbr,
itpitems.medium_desc,
itpitems.series_abbr,
itpitems.series_desc,
itpitems.voicing_desc,
itpitems.pianolevel_desc,
itpitems.bandgrade_desc,
itpitems.category_code,
itprank.overall_ranking,
itpitnam.name AS artist,
itpitnam.type_code
FROM itpitems
INNER JOIN itprank ON ( itprank.item_number = itpitems.identifier )
INNER JOIN itpitnam ON ( itpitems.identifier = itpitnam.item_number )
WHERE mainprice >1
The results are actually not complete duplicates. itpitnam.type_code has a different result in the otherwise duplicated results.
Since adding GROUP BY to the end of the query is causing too much strain on the server (It's searching through about 300,000 records) what else can I do?
Can this be re-written as a sub-query? I just can't figure out how to eliminate the 2nd instances where type_code has changed.
Thank you for your help and assistance.
I also tried SELECT DISTINCT itpitems.identifier, but this served out the same results and had the duplicates (where type_code was the only difference). I don't want the second instance where type_code has changed. I just want one result per identifier regardless of whether or not type_code has multiple instances.
Without seeing examples of the output, hard to say. But have you tried the same exact query with a simple DISTINCT added to the SELECT?
SELECT DISTINCT itpitems.identifier, itpitems.name, itpitems.subtitle, itpitems.description, itpitems.itemimg, itpitems.mainprice, itpitems.upc, itpitems.isbn, itpitems.weight, itpitems.pages, itpitems.publisher, itpitems.medium_abbr, itpitems.medium_desc, itpitems.series_abbr, itpitems.series_desc, itpitems.voicing_desc, itpitems.pianolevel_desc, itpitems.bandgrade_desc, itpitems.category_code, itprank.overall_ranking, itpitnam.name AS artist, itpitnam.type_code
FROM itpitems
INNER JOIN itprank ON ( itprank.item_number = itpitems.identifier )
INNER JOIN itpitnam ON ( itpitems.identifier = itpitnam.item_number )
WHERE mainprice >1

MySql Multiple Tables query

I wonder if any can help me understand something I'm trying to solve.
I'm working on a wordpress site but this is more a sql question as I'm just querying to get some results within a template file.
I have a gallery of pictures which are advert boxes, and I need to pull these in relation to a supplied movie name, to do this Im using some custom fields on the ad pic called 'adlink' (link off ad) and ad
I'm using the nextgen gallery plugin and querying those tables, and I have three tables in total that contain the data I need to query.
ngg_pictures, nggcf_field_values & nggcf_fields.
the nggcf tables are custom fields tables,
I have got so far I can get what I need in two seperate queries, but I can't combine these into one query as it means querying the nggcf_field_values table twice, which I can't seem to sort.
I have hardcoded the search criteria in for the mo, but the 'close-encounters' bit would be a passed var, and the '156' would be the pid from the first query.
SELECT `eg_ngg_pictures`.`filename`, `eg_nggcf_field_values`.`fid`, `eg_nggcf_field_values`.`pid`
FROM eg_ngg_pictures, eg_nggcf_field_values
WHERE ((`eg_nggcf_field_values`.`field_value` LIKE 'close-encounters') AND (`eg_nggcf_field_values`.`pid` = eg_ngg_pictures.pid))
SELECT `eg_nggcf_field_values`.`field_value`
FROM eg_nggcf_field_values, eg_nggcf_fields
WHERE ((`eg_nggcf_fields`.`field_name` = 'adlink') AND (`eg_nggcf_fields`.`id` = eg_nggcf_field_values.fid) AND (`eg_nggcf_field_values`.`pid` = '156'))
any help would be greatly appreciated, I can get the results with what I have, but I like to understand how to combine these two and write better SQl. Thanks MRO
After looking at the Wordpress extension, I think the eg_nggcf_fields is the table that contains the name for a custom field. The eg_nggcf_field_values table contains the values of that custom field per picture.
So if you're looking for two fields called moviename and adlink, you have to look up two rows in the field_values table. You can join a table twice if you give it a different alias:
select pic.filename
, pic.pid
, fv1.field_value as MovieName
, fv2.field_value as Adlink
from eg_ngg_pictures pic
inner join -- Find ID for the field called 'moviename'
eg_nggcf_fields f1
on f1.field_name = 'moviename'
inner join -- Find value for field moviename for this picture
eg_nggcf_field_values as fv1
on fv1.pid = pic.pid
and fv1.fid = f1.fid
inner join -- Find ID for the field called 'adlink'
eg_nggcf_fields f2
on f2.field_name = 'adlink'
inner join -- Find value for field adlink for this picture
eg_nggcf_field_values as fv2
on fv2.pid = pic.pid
and fv2.fid = f2.fid
where fv1.field_value like 'close-encounters'
First of all, I'd recommend sticking to modern ANSI syntax for JOINing tables, which means using the JOIN clause.
Instead of using:
FROM table1, table2 WHERE table1.id = table2.pid
use:
FROM Table 1 JOIN table2 ON table1.id = table2.id
For simplicity's sake, I'd also recommend you to alias tables, as that tends to make the code more readable. Instead of having to write out egg_ngg_pictures every time, you can simply refer to the alias you assign it instead.
Lastly, when you use a LIKE operator, you usually add a wild-card character (typically %. I.e. LIKE '%123' or LIKE '123%'). You seem to look only for complete matches, which means you can just stick to using =, as that should give you slightly better performance.
Now to rewrite your query, I'd use something like the following:
SELECT
pic.filename
, fieldval.fid
, fieldval.pid
, fieldval.field_value
FROM
eg_ngg_pictures pic
JOIN eg_nggcf_field_values fieldval ON fieldval.pid = pic.pid
JOIN eg_nggcf_fields fields ON fields.id = fieldval.fid
WHERE
((fieldval.field_value = 'close-encounters')
AND fields.field_name = 'ad_link'
Note that I am not able to test the query, as I do not have your schema. But by incorporating the two queries into a single query, the join on the field_Values.PID retreieved with the 'close_encounters' value should already exist.
If the query does not work, feel free to create a SQL fiddle with the relevant tables and some data, and I'll try and get it to work with that.

Why are CodeIgniter Active Record and phpMyAdmin giving different results?

SELECT accounts.NameSurname, Projects.Name, personnels.NameSurname
FROM accounts
JOIN projects ON ( accounts.Id = projects.AccountId )
JOIN projectpersonnels ON ( projects.Id = projectpersonnels.ProjectId )
JOIN accounts AS personnels ON ( projectpersonnels.AccountId = personnels.Id )
results in NameSurname Name NameSurname colums
Why would the queries above and below result in different "columns" titles and number of columns?
I am running the query above in phpmyadmin.
using mysql and codeigniter 1.7.3
$this->db->select('accounts.NameSurname,projects.Name,personnels.NameSurname');
$this->db->from('accounts');
$this->db->join('projects','accounts.Id = projects.AccountId' );
$this->db->join('projectpersonnels','projects.Id = projectpersonnels.ProjectId');
$this->db->join('accounts as personnels','projectpersonnels.AccountId = personnels.Id');
$q=$this->db->get();
results in: NameSurname (which is personnel) Name (which is project)
Thank you for reading and replying.
It has to do with how CI creates results. You have a name collision. Both of the NameSurnames are trying to be assigned to the same "key" in your object/array result. Since personnels.NameSurname is second, it is overwriting the value of accounts.NameSurname (because it is being assigned to the same key). If you were to use accounts.NameSurname as aNameSurname (not 100% sure if that is correct syntax for MySQL) instead of accounts.NameSurname that would likely make your results consistent.
This would actually cause the same problem with the PDO classes in certain circumstances too: FETCH_ASSOC and FETCH_OBJ would both only show two columns, but FETCH_ARRAY would show three. FETCH_BOTH would result in there being three numeric indexes and two associative indexes. (Not that you asked about PDO's, but I thought it might further illustrate the point).