many-to-many relationship select checkboxes in form php - php

I have 3 tables: table with objects (A), table with properties (B) and a table with links object/property (A.id, B.id). The problem is that when I need to edit the object, I need to load data into the form, including the checkboxes state. As one of the possible solutions I see is to select data from the table with properties and from the table with objects and then write down the checkboxes using the nested loops, where the main loop will generate checkboxes and the subloop will be looking through the array of selections and will check the checkbox on id match, but I think there must be some way to select the data from the tables.
An example of data:
A.id B.id C(A.id B.id)
1 1 1 1
2 2 1 2
3 1 3
4 1 4
5
What I want to get is:
B.id A.id
1 1
2 1
3 1
4 1
5 NULL
So the B items with indexes 1,2,3,4 will be checked and 5 is unchecked. I've got this by using
SELECT DISTINCT B.id, A.id FROM B LEFT JOIN C ON B.id=C.id
WHERE A.id=<object id to edit> OR A.id IS NULL GROUP BY B.id
And it actually worked, but only for A.id=1. And with A.id=2 i've got
B.id A.id
5 NULL
Which means for me show only one unselected checkbox for property with id 5.
Instead of something like:
B.id A.id
1 NULL
2 NULL
3 NULL
4 NULL
5 NULL
With A.id=2. Is there any way to achieve this or maybe I should use different logic?

Instead of using WHERE clause, you can specify needed A.id in joining condition.
SELECT DISTINCT B.id, C.a_id FROM B LEFT JOIN C ON B.id=C.b_id AND C.a_id=2 GROUP BY B.id
Try this out here: http://sqlfiddle.com/#!2/68efa/13/0

You can use a CASE without using the WHERE clause
SELECT tableb.`id`,
(CASE WHEN tablec.`aid`=2 THEN tablec.`aid` ELSE NULL END ) AS test
FROM tableb
LEFT JOIN tablec ON (tableb.`id` = tablec.`bid`)
Fiddle for id=2
Fiddle for id=1
It will work and gives you result in all conditions that you have the matched ids or not

Related

Combine columns from different tables and assign to new table

I am working on a small project, where I have 2 different tables, which shows the inventory count of users A and B. Consider the table names to be the same. In each table, I have a column called count, which indicates the respective inventory count of each user. So:
A.item | A.count B.item | B.count C.item | c.count
XYZ | 25 XYZ | 31 XYZ | 0
I have a third table C, which has an empty count at the moment. As you can see, the item name (or an id) is common for all 3 tables. What I want to do, is to add the count for users A and B, and then assign it to C. So, what I think I should be doing is;
UPDATE C set count = A.count + B.count WHERE A.item = B.item
Obviously the above syntax doesn't work. The only thing I've managed to get going so far, is to just show the respective counts from both the table, by using the following code:
SELECT A.count, B.count
FROM A
INNER JOIN B ON A.item = B.id
LIMIT 0 , 30
But with the above code, I don't know how to proceed, so that I can sum the counts from A and B, then assign it to C.count. I tried using a while loop in php, and going through each count row by row - querying over and over, but it takes a long time, and it usually times out, based on the default php timeout setting.
Any help would really be appreciated.
Edit: The above question has been clearly answered by Tim. I'm wondering, how do I modify Tim's code, so that, instead of the count, now I have 2 columns with strings. So:
A.item | A.comment B.item | B.comment C.item | c.comment
XYZ | 25 XYZ | 31 XYZ | 0
How do I modify Tim's code to take the comments from A and B, and add them to C? I tried the following:
UPDATE C c
LEFT JOIN A a
ON a.item = c.item
LEFT JOIN B b
ON b.item = c.item
SET c.comment = COALESCE(a.comment, 0) + COALESCE(b.comment, 0)
But it doesn't seem to be this straight forward. I tried looking up the documentation for COALESCE, but i was not able to relate it to this issue I'mm having now, with string. Any help?
Join the three tables together by item, and then update the count of C as being the sum of the other two.
UPDATE C c
LEFT JOIN A a
ON a.item = c.item
LEFT JOIN B b
ON b.item = c.item
SET c.count = COALESCE(a.count, 0) + COALESCE(b.count, 0)
I used left join only in the above update, in case a given item in C have only a count in A but not B, or vice-versa. If you instead want the count to be assigned only if both A and B have counts, then replace the left joins with inner joins.
Actually, following on from Tim's code, this code solves my updated question - i.e. joining strings.
UPDATE C c
LEFT JOIN A a
ON a.item = c.item
LEFT JOIN B b
ON b.item = c.item
SET c.comment = CONCAT(c.comment, a.comment, b.comment);

how to get the result from database in following format in php

Looking for sql query which will solve the following query. I have table employees with following fields:
sno name managerid
1 a 2
2 b 3
3 c 4
and so on.
Now I want to display the data in the following way:
name managername
a b
b c
c d
How to do this using PHP and MySQL?
You can use this query which has self join.
select
t1.name, t2.name As managername
from
table_name t1
inner join table_name t2
on t1.managerid = t2.sno
Hope this will work

create a result set difference between two tables in Mysql

I have two table suppose products and auto_assign_prod_list. I want to populate a dropdown list with the id of products table that are not present in auto_assign_prod_list table.
Suppose,
product table contain
Id
------
1
2
3
4
5
auto_assign_prod_list table contain
Id
-----
1
5
So, my result set will be
2
3
4
How is it possible using MySQL and PHP ?
Try this:
SELECT Id FROM product
WHERE Id NOT IN (SELECT Id FROM auto_assign_prod_list)
It will select the ids from product table which are not in auto_assign_prod_list table.
Result:
Id
------
2
3
4
See result in SQL Fiddle.
use a left join
select p.id
from products p
left join auto_assign_prod_list a on a.id = p.id
where a.id is null
SQLFiddle demo
See this great explanation of joins

MYSQL multiple grouping with join

SELECT
p.product,
q.format,
p.title
FROM
product p
JOIN info q ON p.product = q.product
WHERE p.user='$user'
GROUP BY p.product,q.format
I want to first group by 'product' from the product table but the also by format on the info table.
This is to not show duplicates of format and product. At the moment only the grouping by product is working.
Table - products
product | title
0 one
1 two
1 two - a
2 three
Table - product_details
product | title | format |
0 one home
1 two home
1 two - a home
2 three work
So for this example I want a list like:
product | title | format
0 one home
2 three work
Instead of:
product | title | format
0 one home
1 two home
2 three work
After your table structures were posted, I can see what your intent is, I believe. It looks like you are attempting to limit your output result set to those values for product.product which are never repeated. That is, values for product.product which have exactly one product.title.
For that, you can use a GROUP BY aggregation to return only those with COUNT(*) = 1 after the group is applied.
In this case, since you only expect one row back per product.product anyway, you can do the aggregation at the top level, not requiring a subquery. If you had joined in other tables, and ended up getting multiple rows back per product due to other one-to-many relationships, you would need to use the subquery method instead (to be portable anyway - MySQL would still probably allow this)
SELECT
p.product,
q.format,
p.title
FROM
products p
JOIN product_details q ON p.product = q.product
GROUP BY
p.product,
q.format,
p.title
HAVING COUNT(*) = 1
Here is a demonstration: http://sqlfiddle.com/#!2/72eda/6
If you did expect multiple rows back per p.product, such as if you joined in additional one-to-many related tables, an efficient way to handle that is to perform a JOIN against a subquery that imposes that limit in the HAVING clause. Those which don't meet the HAVING condition won't be returned in the subquery and therefore get discarded by the INNER JOIN.
SELECT
p.product,
q.format,
p.title
FROM
products p
INNER JOIN product_details q ON p.product = q.product
/* Subquery returns only product values having exactly 1 row */
INNER JOIN (
SELECT product
FROM products
GROUP BY product
HAVING COUNT(*) = 1
) pcount ON p.product = pcount.product
WHERE p.user = '$user'
http://sqlfiddle.com/#!2/72eda/2

What's wrong with my MySQL query?

I'm not getting any errors as such just a minor performance issue.
EXPLAIN
SELECT
a.nid,
a.title,
a.uid,
b.parent,
b.weight,
c.name,
d.value
FROM table1 AS a INNER JOIN table2 AS b ON a.vid = b.vid AND a.status = 1
INNER JOIN table3 AS c ON c.uid = a.uid
INNER JOIN table4 AS d ON d.content_id = a.nid AND d.value_type = 'percent' AND d.function = 'average'
When I look at which tables are being referenced, everything is fine, but from table4 where it should only be selecting the "value" field, I'm getting an ALL being called...
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE a ref PRIMARY,vid,status,uid,node_status_type,nid status 4 const 1
1 SIMPLE b eq_ref PRIMARY PRIMARY 4 databasename.a.vid 1
1 SIMPLE c eq_ref PRIMARY PRIMARY 4 databasename.a.uid 1 Using where
1 SIMPLE d ALL NULL NULL NULL NULL 2 Using where
As you can see, it's selecting * from the final table (d). Why is it doing this when I only need ONE field selected from it? Can anyone help me out?
ALL means all rows, not all columns. Since it says there are no possible keys, I'd guess that you don't have an index on d.content_id or d.value_type or d.function.
If you wanted to be fancy, you could put an index across all 3 of those columns.
Are d.value_type and d.function indexed fields? That would be initial instinct as to the cause.
Add a multi-column index to table4 based on the content_type, value_type and function columns.
Your query isn't selecting all the columns from table4, it's selecting all the rows; this isn't much of a problem when there's only two.
Note that a MySQL query execution plan might not give the give the answer you expect when you're working with a small number of records; it can be faster for the database to do a full table scan in those circumstances.

Categories