I have a table in mysql in this structure
table: member
| Id | Name | Lastname | Username
| --------------------------------
| 1 | Alexi| Lalas | alexi
| 2 | Jack | Louis | louis
And I have a table called member images with this structre:
table: image
| Id | MemberId | Image | Type |
|------------------------------------|
| 50 | 1 | face.jpg |Avetar |
| 51 | 1 | image.jpg |Gallery|
| 52 | 2 | main.jpg |Avetar |
| 53 | 2 | jungle.jpg |Gallery|
And I want to get this result
| Id | Name | Lastname | Username | Image1 | Image2 |
|-------------------------------------------------------|
| 1 | Alexi| Lalas | alexi |face.jpg |image.jpg |
| 2 | Jack | Louis | louis |main.jpg |jungle.jpg|
Becuase of some reasons I can't handle is on app side and I have to do it on sql side.
Imagin that I always have 2 type of images and we always have Image1 and Image2.
Any help would be appritiated.
Since they are only two types, you can use the CASE expression to do so. Something like this:
SELECT
m.Id,
m.Name,
m.LastName,
m.UserName,
MAX(CASE WHEN i.Type = 'Avetar' THEN i.Image END) AS 'Image1',
MAX(CASE WHEN i.Type ='Gallery' THEN i.Image END) AS 'Image2'
FROM member AS m
LEFT JOIN image AS i ON m.Id = i.MemberId
GROUP BY m.Id,
m.Name,
m.LastName,
m.UserName;
Note that: LEFT JOIN will include all the members from the member table even if they have no images in the image table, in this case NULL will be returned.
See it in action here:
SQL Fiddle Demo
The way to do this is via a subselect (subquery). You would subselect the first column as the image for the user withe Avetar type and the other column subselect would be for the image with the type Gallery. If you can't find a way to make User ID and Type unique in your sub table then you are going to have issues with this type of query. Keep in mind that a subselects can impact performance heavily.
http://dev.mysql.com/doc/refman/5.0/en/subqueries.html
Related
I have the following simplified tables:
statistics
+-------------+-------------+---------------+
| type | itemnumber | borrowernumber |
+-------------+-------------+---------------+
| issue | 26191 | 11978 |
+-------------+-------------+---------------+
| issue | 26190 | 11979 |
+-------------+-------------+---------------+
items:
+-------------+-------------+
| itemnumber | bibliono |
+-------------+-------------+
| 26191 | 27 |
+-------------+-------------+
| 26190 | 28 |
+-------------+-------------+
biblio_metadata:
+-------------+----------------------------------------------------+
| bibliono | metadata |
+-------------+----------------------------------------------------+
| 27 | <?xml.. <datafield tag="082" ind1="0" ind2="4"> |
| <subfield code="a">005.133/M29</subfield> |
| </datafield> |
+-------------+----------------------------------------------------+
| 28 | <?xml.. <datafield tag="082" ind1="0" ind2="4"> |
| <subfield code="a">995.133/M29</subfield> |
| </datafield> |
+-------------+----------------------------------------------------+
borrowers
+-------------+-------------+
| borrowerno | sort1 |
+-------------+-------------+
| 11978 | CAS |
+-------------+-------------+
| 11979 | CBA |
+-------------+-------------+
I want to get the following through a mysql query:
+-------------+------------+
| DDC Range | CAS | CBA |
+-------------+------------
| 001-100 | 1 | |
+-------------+------------
| 900-999 | | 1 |
+-------------+-----------+
I'm trying to find the right combination of queries - if it's mysql select query multiple columns or any other keyword but can't seem to get the right term to search.
I have the following made up mysql queries but can't go pass the first column 'CAS' and further query the other sort1's (in this example CBA).
SELECT CASE
WHEN ExtractValue(metadata, '//datafield[#tag="082"]/subfield[#code="a"]') REGEXP '^[0]{1}[0-9]{2}[^0-9]+.*' THEN "000-099"
WHEN ExtractValue(metadata, '//datafield[#tag="082"]/subfield[#code="a"]') REGEXP '^[9]{1}[0-9]{2}[^0-9]+.*' THEN "900-999"
ELSE "Others"
END as "DDC Range", count(borrowers.sort1)
from statistics s
LEFT JOIN items on (s.itemnumber=items.itemnumber)
LEFT JOIN biblio_metadata ON (items.biblionumber=biblio_metadata.biblionumber)
LEFT JOIN borrowers on (s.borrowernumber=borrowers.borrowernumber)
WHERE s.type = "issue"
AND borrowers.sort1="CAS"
GROUP BY Subjects
I'm looking into this COUNT(*) from multiple tables in MySQL but I don't know where to put the next query or if what I'm trying to arrive at is related to the aforementioned link. Thanks in advance
Looks like in your query you're filtering out all entries where borrowers.sort1="CAS" but if I understand correctly you'll need these.
Can't you just do all the joins as specified in your question and then use two case statements? As it seems you're interested in the count(*) per subject you can then sum them.
Maybe try something like below:
SELECT
CASE
WHEN ExtractValue(metadata, '//datafield[#tag="082"]/subfield[#code="a"]') REGEXP '^[0]{1}[0-9]{2}[^0-9]+.*' THEN "000-099"
WHEN ExtractValue(metadata, '//datafield[#tag="082"]/subfield[#code="a"]') REGEXP '^[9]{1}[0-9]{2}[^0-9]+.*' THEN "900-999"
ELSE "Others"
END as "DDC Range", count(borrowers.sort1),
sum(case when borrowers.sort1="CAS" then 1 else '' end) as 'CAS',
sum(case when borrowers.sort1="CBA" then 1 else '' end) as 'CBA'
from statistics s
LEFT JOIN items on (s.itemnumber=items.itemnumber)
LEFT JOIN biblio_metadata ON (items.biblionumber=biblio_metadata.biblionumber)
LEFT JOIN borrowers on (s.borrowernumber=borrowers.borrowernumber)
WHERE s.type = "issue"
GROUP BY Subjects
I know it's an already done question, but all the answer I found do not suits my needs and, more of this, I am unable to tail a proper solution by myself.
I explain the situation:
2 tables (user, user_preferences)
in the first one there's, as you probably guessed, the name, last name, id and login (there's more data but theese are the ones I need) and in the second one we have user_id, preferences_key and preferences_value.
If I run my query:
select a.id, a.login, a.first_name, a.last_name, b.preferences_key from users a, user_preferences b where a.id=b.user_id and b.preferences_key like 'msg%';
I receive back an answer like this:
+----+---------+---------------+---------------+----------------------+
| id | login | first_name | last_name | preferences_key |
+----+---------+---------------+---------------+----------------------+
| 4 | usrn1 | User1 | NumberOne | msg002 |
| 7 | usrn5 | User5 | NumberFive | msg001 |
| 7 | usrn5 | User5 | NumberFive | msg002 |
| 10 | usrn9 | User0 | NumberNine | msg002 |
+----+---------+---------------+---------------+----------------------+
I'm trying to figure out how to switch from this view to this one:
+----+---------+---------------+---------------+--------+--------+
| id | login | first_name | last_name | msg001 | msg002 |
+----+---------+---------------+---------------+--------+--------+
| 4 | usrn1 | User1 | NumberOne | No | Yes |
| 7 | usrn5 | User5 | NumberFive | Yes | Yes |
| 10 | usrn9 | User0 | NumberNine | No | Yes |
+----+---------+---------------+---------------+--------+--------+
If you have any suggestion will be very appreciated, and, by the way, if you can add some more explanation I'll appreciate it even more.
Thank you
There isn't really an easy way to pivot a table like you want easily that I know of.
There is the following manual approach by JOINing to the same table multiple times. Something like the following should work:
SELECT
a.id, a.login, a.first_name, a.last_name,
IF(b1.preferences_key IS NULL, 'No', 'Yes') msg001,
IF(b2.preferences_key IS NULL, 'No', 'Yes') msg002
FROM
users a
LEFT JOIN user_preferences b1
ON b1.user_id = a.id
AND b1.preferences_key = 'msg001'
LEFT JOIN user_preferences b2
ON b2.user_id = a.id
AND b2.preferences_key = 'msg002';
If this doesn't help. check out MySQL pivot table
I have these tables in my MySQL database:
General table:
+----generalTable-----+
+---------------------+
| id | scenario | ... |
+----+----------+-----+
| 1 | facebook | ... |
| 2 | chief | ... |
| 3 | facebook | ... |
| 4 | chief | ... |
Facebook Table:
+----facebookTable-----+
+----------------------+
| id | expiresAt | ... |
+----+-----------+-----+
| 1 | 12345678 | ... |
| 3 | 45832458 | ... |
Chief Table:
+------chiefTable------+
+----------------------+
| id | expiresAt | ... |
+----+-----------+-----+
| 2 | 43547343 | ... |
| 4 | 23443355 | ... |
Basically, the general table holds some (obviously) general data. Based on the generalTable.scenario you can look up more details in the other two tables, which are in some columns familiar (expiresAt for example) but in others not.
My question is, how to get the joined data of generalTable and the right detailed table in just one query.
So, I would like a query like this:
SELECT id, scenario, expiresAt
FROM generalTable
JOIN facebookTable
ON generalTable.id = facebookTable.id
JOIN chiefTable
ON generalTable.id = chiefTable.id
And an output like this:
| id | scenario | expiresAt |
+----+----------+-----------+
| 1 | facebook | 12345678 |
| 2 | chief | 43547343 |
| 3 | facebook | 45832458 |
| 4 | chief | 23443355 |
However, this doesn't work, because both facebookTable and chiefTable have ambiguous column name "expiresAt". For the ease of use I want to keep it that way. The result table should also only have one column "expiresAt" that is automatically filled with the right values from either facebookTable or chiefTable.
You might want to consider adding expiredAt to your general table, and removing it from the others, to remove duplication in the schema, and to make this particular query simpler.
If you need to stick with your current schema, you can use table aliases to resolve the name ambiguity, and use two joins and a union to create the result you are looking for:
SELECT g.id, g.scenario, f.expiresAt
FROM generalTable g
JOIN facebookTable f
ON g.id = f.id
UNION ALL
SELECT g.id, g.scenario, c.expiresAt
FROM generalTable g
JOIN chiefTable c
ON g.id = c.id;
The outer join approach mentioned in another answer would also solve the problem.
One way you could accomplish it is with LEFT JOIN. In the result fields you can do something like this for common fields IF(fTbl.id IS NULL, cTbl.expiresAt, fTbl.expiresAt) AS expiresAt.
Some background: an 'image' is part of one 'photoshoot', and may be a part of zero or many 'galleries'. My tables:
'shoots' table:
+----+--------------+
| id | name |
+----+--------------+
| 1 | Test shoot |
| 2 | Another test |
| 3 | Final test |
+----+--------------+
'images' table:
+----+-------------------+------------------+
| id | original_filename | storage_location |
+----+-------------------+------------------+
| 1 | test.jpg | store/test.jpg |
| 2 | test.jpg | store/test.jpg |
| 3 | test.jpg | store/test.jpg |
+----+-------------------+------------------+
'shoot_images' table:
+----------+----------+
| shoot_id | image_id |
+----------+----------+
| 1 | 1 |
| 1 | 2 |
| 3 | 3 |
+----------+----------+
'gallery_images' table:
+------------+----------+
| gallery_id | image_id |
+------------+----------+
| 1 | 1 |
| 1 | 2 |
| 2 | 3 |
| 3 | 1 |
| 4 | 1 |
+------------+----------+
What I'd like to get back, so I can say 'For this photoshoot, there are X images in total, and these images are featured in Y galleries:
+----+--------------+-------------+---------------+
| id | name | image_count | gallery_count |
+----+--------------+-------------+---------------+
| 3 | Final test | 1 | 1 |
| 2 | Another test | 0 | 0 |
| 1 | Test shoot | 2 | 4 |
+----+--------------+-------------+---------------+
I'm currently trying the SQL below, which appears to work correctly but only ever returns one row. I can't work out why this is happening. Curiously, the below also returns a row even when 'shoots' is empty.
SELECT shoots.id,
shoots.name,
COUNT(DISTINCT shoot_images.image_id) AS image_count,
COUNT(DISTINCT gallery_images.gallery_id) AS gallery_count
FROM shoots
LEFT JOIN shoot_images ON shoots.id=shoot_images.shoot_id
LEFT JOIN gallery_images ON shoot_images.image_id=gallery_images.image_id
ORDER BY shoots.id DESC
Thanks for taking the time to look at this :)
You are missing the GROUP BY clause:
SELECT
shoots.id,
shoots.name,
COUNT(DISTINCT shoot_images.image_id) AS image_count,
COUNT(DISTINCT gallery_images.gallery_id) AS gallery_count
FROM shoots
LEFT JOIN shoot_images ON shoots.id=shoot_images.shoot_id
LEFT JOIN gallery_images ON shoot_images.image_id=gallery_images.image_id
GROUP BY 1, 2 -- Added this line
ORDER BY shoots.id DESC
Note: The SQL standard allows GROUP BY to be given either column names or column numbers, so GROUP BY 1, 2 is equivalent to GROUP BY shoots.id, shoots.name in this case. There are many who consider this "bad coding practice" and advocate always using the column names, but I find it makes the code a lot more readable and maintainable and I've been writing SQL since before many users on this site were born, and it's never cause me a problem using this syntax.
FYI, the reason you were getting one row before, and not getting and error, is that in mysql, unlike any other database I know, you are allowed to omit the group by clause when using aggregating functions. In such cases, instead of throwing a syntax exception, mysql returns the first row for each unique combination of non-aggregate columns.
Although at first this may seem abhorrent to SQL purists, it can be incredibly handy!
You should look into the MySQL function group by.
I am trying to do multiple joins on the same MySQL table, but am not getting the results that I expect to get. Hopefully someone can point out my mistake(s).
Table 1 - cpe Table
|id | name
|----------
| 1 | cat
| 2 | dog
| 3 | mouse
| 4 | snake
-----------
Table 2 - AutoSelect
|id | name | cpe1_id | cpe2_id | cpe3_id |
|-----------------------------------------------
| 1 | user1 | 1 | 3 | 4 |
| 2 | user2 | 3 | 1 | 2 |
| 3 | user3 | 3 | 3 | 2 |
| 4 | user4 | 4 | 2 | 1 |
------------------------------------------------
I would like to see an output of
user1 | cat | mouse | snake |
user2 | mouse | snake | dog |
..etc
Here is what I have tried
SELECT * FROM AutoSelect
LEFT JOIN cpe ON
( cpe.id = AutoSelect.cpe1_id ) AND
( cpe.id = AutoSelect.cpe2_id ) AND
( cpe.id = AutoSelect.cpe3_id )
I get blank results. I thought i knew how to do these joins, but apparently when I'm trying to match cpe?_id with the name of the cpe table.
Thanks in advance for any assistance.
You need left join 3 times as well. Currently your query only joins 1 time with 3 critieria as to the join. This should do:
SELECT a.name, cpe1.name, cpe2.name, cpe3.name FROM AutoSelect as a
LEFT JOIN cpe as cpe1 ON ( cpe1.id = a.cpe1_id )
LEFT JOIN cpe as cpe2 ON ( cpe2.id = a.cpe2_id )
LEFT JOIN cpe as cpe3 ON ( cpe3.id = a.cpe3_id )
And you probably mean to INNER JOIN rather than LEFT JOIN unless NULL values are allowed in your AutoSelect table.
I think your design is wrong.
With tables like that, you get it the way it's meant to be in relational databases :
table 1 : animal
id name
1 cat
2 dog
3 mouse
4 snake
table 2 : user
|id | name |
|--------------
| 1 | user1 |
| 2 | user2 |
| 3 | user3 |
| 4 | user4 |
table 3 : association
|id_user | id_animal|
|--------------------
| 1 | 1 |
| 1 | 3 |
| 1 | 4 |
| 2 | 3 |
| 2 | 1 |
| 2 | 2 |
| 3 | 3 |
| 3 | 2
| 4 | 4 |
| 4 | 2 |
| 4 | 1 |
---------------------
Then :
select u.name, a.name from user u, animal a, association ass where ass.user_id = u.id and ass.animal_id = a.id;
In this case, your solution won't produce a good dynamic database. There are other ways to make combinations of multiple tables. I can show you by my own database what you should use and when you should use this solution. The scheme is in dutch, but you'll probably understand the keywords.
Like you, I had to combine my windmills with a kWh-meter, which has to measure the energyproduction of my windmills. What you should do, is this case, is making another table(in my case molenkWhlink). Make sure your tables are INNODB-types(for making Foreign keys). What I've done is combining my meters and mills by putting a pointer(a foreign key) of their ID(in Dutch Volgnummer) in the new table. An advantage you may not need, but I certainly did, is the fact I was able to extend the extra table with connection and disconnection info like Timestamps and metervalues when linking or unlinking. This makes your database way more dynamic.
In my case, I Also had a table for meassurements(metingoverzicht). As you can see in the scheme, I've got 2 lines going from Metingoverzicht to molenkwhlink. The reason for this is quite simple. All meassurements I take, will be saved in table Metingoverzicht. Daily meassurements(which are scheduled) will have a special boolean put on, but unscheduled meassurements, will also me saved here, with the bollean turned off. When switching meters, I need the endvalue from the leaving meter and the startvalue from the new meter, to calculate the value of todays eneryproduction. This is where your solution comes in and an extra table won't work. Usually, when you need just one value from another table a JOIN will be used. The problem in this case is, I've got 2 meassurementIDs in 1 link(1 for connecting and 1 for disconnecting). They both point to the same tablecolumn, because they both need to hold the same type of information. That is when you can use a double JOIN from one table towards the other. Because, both values will only be used once, and just needed to be saved in a different place to avoid having 1 action stored on different locations, which should always be avoided.
http://s1101.photobucket.com/user/Manuel_Barcelona/media/schemedatabase.jpg.html