MySQL query to linked 2 tables - mysql

This question was migrated from Super User because it can be answered on Stack Overflow.
Migrated last month.
I have these 2 tables in MySQL:
Table ___Photos:
AMP_Id
AMP_Photo
AMP_Formats
1
dog.jpg
1,2
1
cat.jpg
3
Table ___Formats:
AMF_Id
AMF_Format
1
10x10
2
30x30
3
40x40
How can I list each Photos with the formats linked in ___Formats?
For example, for the tables show above, I would need something like this:
AMP_Photo
AMF_Format
dog.jpg
10x10,30x30
cat.jpg
40x40
This is what I have tried so far:
SELECT
AMP_Photo,
IFNULL(GROUP_CONCAT(AMF_Format), "") as list_formats
FROM ___Photos i
LEFT JOIN ___Formats f
ON f.AMF_Id = AMF_Format
GROUP BY AMP_Photo
ORDER BY AMP_Photo ASC

Related

generate a pivot table out of mysql data with php

I am having problems to figure out, how to make a pivot table with php/mysql.
There is no Code now, its mor to understand how it works.
Lets say i have a Table with packages
Table packages
pack_ID pack_Name
1 ABC
2 XYZ
3 DEF
and so on
Then a Table with Items which are part of the packages
Table items
item_ID item_Name
1 red item
2 blue item
3 green item
4 black item
And a Table to mix them
Table item-pack
pack_ID item_ID
1 2
1 4
2 1
2 3
3 2
3 4
3 3
3 1
And the result should be a pivot table
item/ pack
ABC XYZ DEF
red Item x x
blue Item x x
green Item x x
black Item x x
First i would QUery the Packages with:
SELECT p.pack_ID, p.pack_Name FROM packages
Which should give me and array with the packages.
Then i would run a for each or while and query the items like this
SELECT i.item_ID, i.item_Name FROM item-pack ip
JOIN item i ON i.item_ID = ip.item_ID
WHERE ip.pack_ID = $ValueFromThe QUery
But how the heck do i retun the result as a pivot?
is this so dificult with php?
Thy for any help.

msql count of items in each category into 2 columns by status with join

I’m a mysql newbie, recently installed mariadb to work on a project.
I have one table of many ITEMS, which are in various categories (catnum), and another table, STATUS, showing items (by id#) and their current status, either A or B.
I need to write a query that lists all of the categories (by catnum) and the total of all A’s and B’s in each category, something like this:
Desired result:
catnum statA statB
1001 22 15
1002 0 12
1003 14 8
1004 3 37
1005 24 0
1006 0 1
1007 47 5
etc
The ITEMS table looks like this:
itemid catnum
1 1205
2 1008
3 1010
4 1150
5 1782
6 1553
7 1004
etc
The STATUS table looks like this:
itemid stat
60 A
302 A
95 B
122 B
8 B
6 A
46 B
etc
The itemid in ITEMS is auto_increment, in case that matters.
I know (or think I know) that I need to use the following in some combination:
count(status.stat) or count(status.stat = A)
where items.itemid = status.itemid
where stat = A (then B)
group by catnum.
In some combinations I got error saying “Unknown column 'status.itemid' in 'having clause'” or other clause, despite that it exists. Why is that?
The closest I have gotten is to show each category and both status columns properly labeled but the number of B status items was incorrect, just a repeat of number of A status items.
SELECT
items.catnum,
count(status.stat=1) AS statA,
count(status.stat=2) AS statB
FROM
status
INNER JOIN
items
WHERE
items.itemid = status.itemid
GROUP BY
catnum;
(ALSO tried with ON instead of WHERE, same result, statB totals were wrong.)
I have explored self joins, inner joins, left/right joins, unions, subquery, and other techniques but I can’t seem to get to what I want. It seems like this must be a really common general query, but I can’t seem to find the right search terms to find it online. Any guidance would be appreciated.
Your query as it currently stands will simply return a COUNT of all the items in STATUS which have a given catnum. This is why the values for statA and statB are the same. What you need to do is SUM the occurrences of each status value. I've made a small SQLFiddle demo that shows this query in action:
SELECT
items.catnum,
SUM(status.stat='A') AS statA,
SUM(status.stat='B') AS statB
FROM items
JOIN status
ON items.itemid = status.itemid
GROUP BY items.catnum
Output (for the demo data):
catnum statA statB
1004 1 1
1008 2 1
1010 0 2
Note that in MySQL a boolean expression (e.g. status.stat='A') evaluates to 1 if true, 0 if false, so it can be summed directly.

Limit selected results by unique selected IDs when using left joins

I have a table users and some other tables like images and products
Table users:
user_id user_name
1 andrew
2 lutz
3 sophie
4 michael
5 peter
6 oscor
7 anton
8 billy
9 henry
10 jon
Tables images:
user_id img_type img_url
1 0 url1
1 1 url4
2 0 url5
7 0 url7
8 0 url8
9 1 url9
Table Products
user_id prod_id
1 5
1 55
2 555
8 5555
9 5
9 55
I use this kind of SELECT:
SELECT * FROM
(SELECT user.user_id,user.user_name, img.img_type, prod.prod_id FROM
users
LEFT JOIN images img ON img.user_id = users.user_id
LEFT JOIN products prod ON prod.user_id = users.user_id
WHERE user.user_id <= 5) AS users
ORDER BY user.user_id ASC
The result should be the following output. Due to performance improvements, I use ORDER BY and an inner select. If I put a LIMIT 5 within the inner or outer select, things won't work. MySQL will hard LIMIT the results to 5. However I need the LIMIT of 5 (pagination) found unique user_id results which would lead to 9 in this case.
Can I use maybe an if-statement to push an array with found user_id and break/finish up the select when the array consist of 5 UIDs? Or can I modify somehow the select?
user_id user_name img_type prod_id
1 andrew 0 5
1 andrew 1 5
1 andrew 0 55
1 andrew 1 55
2 lutz 0 5
2 lutz 0 55
3 sophie null null
4 michael null null
5 peter null null
results: 9
LIMIT 5 and user_id <= 5 do not necessarily give you the same results. One reason: There are multiple rows (after the JOINs) for user_id = 1. This is because there can be multiple images and/or multiple products for a given 'user'.
So, first decide which you want.
LIMIT without ORDER BY gives you an arbitrary set of rows. (Yeah, it is somewhat predictable, but you should not depend on it.)
ORDER BY + LIMIT usually implies gathering all the potentially relevant rows, sorting them, then doing the "limit". There are sometimes ways around this sluggishness.
LEFT leads to the NULLs you got; did you want that?
What do you want pagination to do if you are displaying 5 items per page, but user 1 has 6 images? You need to think about this edge case before we can help you with a solution. Maybe you want all of user 1 on a page, even if it exceeds 5? Maybe you want to break in the middle of '1'; but then we need an unambiguous way to know where to continue from for the next page.
Probably any viable solution will not use nested SELECTs. As you are finding out, it leads to "errors". Think of it this way: First find all the rows you need to display on all the pages, then carve out 5 for the current page.
Here are some more musings on pagination: http://mysql.rjweb.org/doc.php/pagination

compare column of two rows of same table in mysql

I have a table name player_history containing history of player. in this table having column player_id, Final_position,meeting_code,race_no and beaten_time. If a player stood a first or second position the time will be same there are meeting code one day and in each meeting code there are maximum 10 races.
I want to select those records where 1st and second position beaten time are not same.
player_id Meeting_Code race_no final_position beaten_time
1 0001 1 1 2
2 0001 1 2 2
1 0001 2 1 5
2 0001 2 2 6
... so on
Output should be:
player_id Meeting_Code race_no final_position beaten_time
1 0001 2 1 5
2 0001 2 2 6
Also if it is not correct I want to update records of first position only.
Let table name be Test. Try to put Self Join or something like this:
Select t1.player_id t1.Meeting_Code t1.race_no t1.final_position t1.beaten_time
From Test t1
LEFT JOIN Test t2 ON t1.beaten_time != t2.beaten_time.
Try like this. It might work.
Check this it will work
SELECT *
FROM table_name
GROUP BY player_id
HAVING count(beaten_time) = 1;
Try It:
select b.player_id,b.meeting_code,b.race_no,b.final_position,b.beaten_time
from player_history a,player_history b
where a.race_no = b.race_no and a.beaten_time != b.beaten_time;

Find all the leaf nodes below a subtree in a Tree structure in sql server

I've a tree structure, and its subsequent assignment table for customer categories in an sql server database.
CustomerCategory (CategoryID, ParentId)
CustomerInCategory(CustomerID, CategoryID)
If a CustomerCategory has any customer assigned to it, we can't add another subcategory to it. So, Customer can only be added to the lowest level in every sub tree. In other sense, the result of this query
SELECT * FROM `CustomerCategory` WHERE `CategoryId` NOT IN
(SELECT DISTINCT `parentid` FROM `CustomerCategory` WHERE `parentid` IS NOT NULL)
would yield leaf nodes. The Other thing is that, this tree might have subtrees of different levels, and we also, don't want to bound the number of levels in anyway, however, our users won't need more than 10 levels. Consider this as an illustration
CategoryID------ParentID---------------Name
1 NULL All Customers
2 1 Domestic
3 1 International
4 2 Independent Retailers
5 2 Chain Retailers
6 2 Whole Sellers
7 5 A-Mart
8 5 B-Mart
9 4 Grocery Stores
10 4 Restaurants
11 4 Cafes
CustomerID---------CustomerName----------Category
1 Int.Customer#1 3
2 Int.Customer#2 3
3 A-Mart.Branch#1 7
4 A-Mart.Branch#2 7
5 B-Mart.Branch#1 8
6 B-Mart.Branch#2 8
7 Grocery#1 9
8 Grocery#2 9
9 Grocery#3 9
10 Restaurant#1 10
11 Restaurant#2 10
12 Cafe#1 11
13 Wholeseller#1 6
14 Wholeseller#2 6
My requirement is something like this, "Given a node in Categories, Return All the Customers attached to any node below it".
How can I do it with sql?
Obviously this can be done with a recursive call in the code, but how can we do it in t-sql (without calling a stored procedure several times or using text-based search)?
Can any body, Use a CTE to solve this problem?
I have a result set of something like this in mind
CustomerID--------Customer Name----------------CategoryId----------CAtegoryName
12 Cafe#1 11 Cafes
12 Cafe#1 4 IndependentRetailers
12 Cafe#1 2 Demoestic
12 Cafe#1 1 AllCustomers
.
.
.
4 A-Mart.Branch#2 7 A-Mart
4 A-Mart.Branch#2 5 Chain Retailers
4 A-Mart.Branch#2 2 Domestic
4 A-Mart.Branch#2 1 All Customers
.
.
.
14 Wholeseller#2 6 WholeSellers
14 Wholeseller#2 2 Domestic
14 Wholeseller#2 1 All Customers
This is not necessarily a good Idea to layout a result like this, This would consume too much space, something that might not be required, yet, a search in such result set would be very fast. If I want to find all the customers below say categoryId = 2 , I would simply query
SELECT * FROM resultset where category ID = 2
Any suggestions to improve the data model is super welcomed! If It helps solving this problem.
Once again, I'm not fixated on this result set. Any other Suggestion that solves the problem,
"Given a node in Categories, Return All the Customers attached to any node below it", is well accepted.
You can use a CTE to recursively build a table containing all the parent-child relationships and use the where clause to get only the subtree you need (in my example, everyting under CategoryId 5) :
WITH CategorySubTree AS (
SELECT cc.CategoryId as SubTreeRoot,
cc.CategoryId
FROM CustomerCategory cc
UNION ALL
SELECT cst.SubTreeRoot, cc.CategoryId
FROM CustomerCategory cc
INNER JOIN CategorySubTree cst ON cst.CategoryId = cc.parentId
)
SELECT cst.CategoryId
FROM CategorySubTree cst
WHERE cst.SubTreeRoot = 5
You can modify this query to add whatever you need, for example, to get customers linked to the category nodes in the subtree :
WITH CategorySubTree AS (
SELECT cc.CategoryId as SubTreeRoot,
cc.CategoryId
FROM CustomerCategory cc
UNION ALL
SELECT cst.SubTreeRoot, cc.CategoryId
FROM CustomerCategory cc
INNER JOIN CategorySubTree cst ON cst.CategoryId = cc.parentId
)
SELECT cst.CategoryId,cic.CustomerId
FROM CategorySubTree cst
INNER JOIN CustomerInCategory cic ON cic.CategoryId = cst.CategoryId
WHERE cst.SubTreeRoot = 5
And of course you can join further tables to get labels and other needed information.