Cakephp SELECT recursive associtations fields by condition - php

This is going to be a long shot, but I have been staring at this for longer then I should have... I have a structure setup like this:
C (hasMany) B (hasMany) A
1 1 1
2 2 2
3 3 3
4 4 4
Where each character is a table, and each number a field of said table record. Field 1 is the primary key called 'id'. My function only takes a single argument, lets call it $X. The following is what should happen:
Find the first record in table C, where field 3 has value $X
Find the first record in table B, where field 2 has the value of A record's field 1
select fields 3 and 4 in table A of all records, where field 2 has the value of B record's field 1
Working with CakePHP has been a blessing with it's more then decent documentation, but beside my lack of properly understanding associations, I find it extremely difficult to make this work recursivly. What am i dong wrong here?
So far ive tried a few variations of the following:
$tableC->find('all')
->select(['val1'=>'A.3',
'val2'=>'A.4',
])
->where(['C.3 = ' => $X])
->innerJoinWith('B')
->innerJoinWith('A')
->toList()
;
I can get whatever values I want from the B table, but anything further then that is where I start getting errors like:
The A association is not defined on C.
Is there anyone that could shed some light on this? Im using CakePHP 3.9.
Thanks in advance!

Related

How to import data from excel file and identify subcategory

I am making the function of importing data from the excel file with the following structure
i want loop the datas of excel then insert to categories table and determined subcategory by value of first column. Eg: 101 is sub category of 1, 101001 is sub of 101,...
I have been thinking for a long time and looking for it but not yet. Hope the helping.
Use PHP Spreadsheet https://phpspreadsheet.readthedocs.io/en/latest/
Reading from a file: https://phpspreadsheet.readthedocs.io/en/latest/topics/reading-files/#reading-files
However you parse the cat/subcat, you would want to insert it back into the table with the database ID of the parent.
To determine the parent, start with the first row, and keep it in a parents array. When you hit the next row, check the parents array if the value exists. You will have to check char by char. Then add every new category to the parents. This structure is not really ideal, what happens when PHP becomes a parent, and so on. PHP should be 10101 at any rate to follow the structure. Ruby 10102
In all honesty, you don't need second half of the number, only the parent. Just use the row id.
1, , Programming
2,1,OOP
3,2,PHP
What you are missing here is the row id. The last part is only the "sort" and can just be removed. Imagine if the column was a fixed length field which would be "easier" to parse. 3 digit for parent, and 3 digits for the sort. Start parsing from the top ..
000001 Programming
001001 OOP
What is PHP now? You aren't pointing to 001 (OOP) cause 001 is also Programming. So adding a row id, you can now point to the id that will be entered into the DB.
1 null 1 Programming # id parent sort name
2 1 1 OOP
3 2 1 PHP
4 2 1 Ruby
5 1 2 Functional

mysql filter rows by field value in linked table

Scenario:
I have a main table, say "items". Each item can be of many types, and I use a table "types" and a linked table to keep the relations between the two, say "items_types" in a typical one to many situation. Now, each type has a supertype, with a straight one to one relation.
items: i_id, i_name
types: t_id, t_name, t_st_id
items_types: it_id, it_i_id, it_t_id
supertypes: st_id, st_name
Now I have to filter all the items that are related to at least one supertype in a given set, say supertypes with ids 1,2,3
I am thinking to use a group_concat on the ids of the related supertypes and then filtering using multiple FIND_IN_SET in or between each other, using a WHERE clause.
However this, if working, would slow down the query and I don't like comparing ids as if they were strings.
Any idea?
You can do like this.
select i.*
from items_types it
join items i on i.i_id = it.it_i_id
join types t on t.t_id = it.it_t_id
join supertypes st on st.st_id = t.t_st_id and st_id in (1,2,3)
I found a better solution: instead using related records to keep track of all the types the item belongs to, I am giving each type a numeric code which can be used in binary comparison, e.g:
Type 1: code 1
Type 2: code 2
Type 3: code 4
Type 4: code 8
Type 5: code 10
I think I gave the idea.
Each item will have a field to keep track of all its types, named 'coded_type'. For example if a field has coded_type 7 it means that it belongs to Type 1, Type 2, Type 3.
For instance, if a user then wants to look for all items that are of type 2 or 3 the query will look for all items whose coded_type field binary ANDed against 6 gives a value greater than zero.
That is:
select * from items where (coded_type & 6)>0
I think this way the query will much simpler and run faster. Sorry I thought of this just now.

Parent/Child MySQL query with CASE/WHEN or switch

I’m using PHP to dynamically add another table to a page based on a parent/child relationship.
I’ve greatly simplified things so lets suppose I have a table 'FAMILY' with three columns Parent Int(6), Child varchar(15), and Fname varchar(25). The table has four rows, whose values are;
Row 1 : 4, NULL , Bill
Row 2: 5, 4, Tom
Row 3: 6, NULL, Frank
Row 4: 7, 4, Sam
As you can tell Tom and Frank are children of Bill. And so Bill is the parent of Tom and Sam.
Regardless of whose record I’m currently looking at, I would like to be able to dynamically see the other associated records as well. Forget the PHP part, I have that working. I just need the MySQL query.
The way I see it, I need one query that will do two different things depending on the value of child.
1: If Child is NULL (or blank) as in Row 1, I need it to return Row 2 and 4 based on the parent value of 4. In other words I’m looking at a Parent.
2) If Child is NOT NULL, as in Rows 2 & 4, I need it to return row 1 and the other row 2 or 4 depending which child I was looking at. Now I’m looking at a child record.
SELECT * FROM FAMILY WHERE
CASE WHEN Child IS NOT NULL then parent = 4
WHEN child IS NULL then child = 4
END
GROUP BY PARENT
I’m pretty sure that I’m using CASE/WHEN incorrectly but after trying about a thousand things I give up and need to ask for help.
Please a MySQL query that can evaluate if it’s a parent or child and then pull the appropriate row(s) would be very much appreciated.
Thanks in advance.
Not much sure from your question statement but you can modify your WHERE condition to be like below
WHERE (Child IS NOT NULL AND parent = 4)
OR COALESCE(child, 4) = 4

MySQL search in field (or other solutions)

I have a table with products that fall under specific categories, but the products within each category can contain multiple meta data tracking field
Table: products
id name category metadata
1 something 1 blue,red,purple
2 something else 2 left,right,middle
I have been trying to contemplate the best method to have a single product table but can't seem to squeeze the metadata in conveniently. for now I have created a table with all the metadata and fields for tracking the related category (the sequence is so i can order them withing a dropdown etc..)
Updated table: products
id name category metadata
1 something 1 1,2,3
2 something else 2 4,5,6
Table: metadata
id category sequence option
1 1 1 blue
2 1 2 red
3 1 3 purple
4 2 1 left
5 2 2 right
6 2 3 middle
If this format makes sense .. I am trying to generate a query that will search for values in my product table and grab each and all of the related meta values. The issue I am having is trying to find a unique value in the products field. if I do a MySQL search for LIKE(%1%) I will get matches for 1, 11, 21, 31 etc ... I thought of adding a leading and trailing comma to the field by default and then search for ",1," which would be unique .. but there has to be a better way ...
Any recommendations (regarding format or query)?
It's not an ideal design to have comma-separated values within a single database field. Aside from the problem you mentioned (difficult to search), your queries will be less efficient, as the DB won't be able to use indices for the lookup.
I'd recommend making a separate table products_metadata with a many-to-one relationship to the products table. Have the *metadata_id*, and the *product_id*, which is a foreign key linking back to the products table. That will make your job much easier.
You want to add another table, which links products to their metadata. It will have two columns: productid and metadataid which refer to the relevant entries in the products and metadata tables respectively. Then you no longer keep metadata in the products table, but JOIN them together as required.

Database design for price data

I have a database that stores components in a component table.
There is a second table for component prices. This table has a field that maps to a component id. My price table needs to store information for a bunch of different prices (10, 100, 1000, 10K, 100K, 1M). The thing is, there is a possibility in the future to store other price types such as 25K or 50K.
As of right now, my price table looks like this:
id component_id type price
where the type can take values from 1-6 currently. This is good because it will allow me to add new price types in the future very easily.
The other option is a price table that looks like this:
id component_id price_10 price_100 price_1000 price_10K price_100K price_1M
But in this case, I would need to add a new field every time a new price type is added.
I hope that people here would agree with the first method.
But using the first method, I'm having trouble displaying a page that would display all my components in my database with the 6 prices it may or may not have (should show 0 in this case). Obviously this would be simple using the second method.
This is the query I have so far:
SELECT * FROM `component` LEFT JOIN `component_cost` ON `cmpcst_component` = `cmp_id`
EDIT:
I thought I would show some sample data from the component price table:
The prices are a unit price for an amount X. X ranges from 10 to 1 million. So I might have something like this in my component price table:
id component_id type price
1 1 1 0.50
2 1 2 0.45
3 1 3 0.40
4 1 4 0.35
5 1 5 0.32
6 1 6 0.30
The first option its much better.
For display the data, create a view with a pivot table.
You can found help here
http://en.wikibooks.org/wiki/MySQL/Pivot_table
Create two tables, one for components and one for compontent's prices (for a minimum count). Then you can add as many prices per component you would like. Now and in the future.
This is a variation of your first example, you just don't hardcode types but has the number that is related to a certain price.
Try something like:
select * from component c join compcst_component cc on true and c.id = cc.cmp_id;
I'm not sure I follow you.. Hope you can give us the table structures, but here's one try:
SELECT c.cmp_id, ISNULL(p.price, 0) AS Price
FROM component AS c INNER JOI component_cost AS p
ON p.cmpcst_component = c.cmp_id
Maybe I don't have the column-to-table matchup right, but try that.

Categories