Build complex result table with dynamic columns - mysql

I have a question - trying to find a solution here, but that what I see is not as my situation. So:
In TABLE1 we have some article descriptions
ID | Name
1 | Doors
2 | Chairs
In TABLE2 we have a article properties
ID |ID_article | Descr
1 |1 | Type
2 |1 | Material
3 |2 | Height
4 |2 | Width
5 |2 | Toll
In TABLE3 we have a article list with properties values like
Article | ID_art_descr | ID_art_prop | Value
Model1 | 1 | 1 | Solid
Model1 | 1 | 2 | Wood
Model2 | 1 | 1 | Solid
Model2 | 1 | 2 | Steel
The goal is to build a table, which list article from given group with properties for that group. for example, for doors, the table must have columns:
Article | Type | Material
Model1 | Solid | Wood
Model2 | Solid | Steel
For Chairs, the table must have other columns:
Article | Height | Width | Toll
........
So for every article group, the columns count and lables will be different. I was write script on aspx and php which do this, but that method have difficults with sorting or filtering the result table (in some case, we have more than 10k ot rows). So I wonder is there a way to generate a result table on MySQL?
And here is the sqlfiddle description for Table1, Table2 and Table3:
http://sqlfiddle.com/#!2/53e32/1
Thank you strawberry

Related

Merge duplicate (row group) column cells

ID| Date1 | Date 2 |Total
-----------------------------------
1 | 15/02/2017 |02/02/2017 | 3 |
-----------------------------------
1 | 15/02/2017 |05/08/2017 | 3 |
-----------------------------------
1 | 15/02/2017 |12/12/2017 | 3 |
-----------------------------------
2 | 12/05/2017 |07/08/2017 | 2 |
-----------------------------------
2 | 12/05/2017 |10/08/2017 | 2 |
I have a table that is displaying data like above. I'm grouping that data on "ID" column. Values for Columns "Date1" & "Total" for a particular "ID" are the same but "Date2" value can be different in a given group.
How can i merge the cells across rows when the values are the same such that it displays like below?
ID| Date1 | Date 2 |Total
-----------------------------------
1 | 15/02/2017 |02/02/2017 | 3 |
--| |------------| |
1 | |05/08/2017 | |
--| |------------| |
1 | |12/12/2017 | |
---------------------------------|
2 | 12/05/2017 |07/08/2017 | 2 |
--| |------------| |
2 | |10/08/2017 | |
I did manage to find that "HideDuplicates" TextBox property, but while that will suppress the repetition of the cell values in adjacent rows it does not merge those duplicate cells down the column across rows
Its difficult to tell how the report is setup in terms of groups etc without seeing the design, but this is pretty simple to do from scratch.
Start with a simple table with just your detail rows, no grouping. Then right-click the detail row in the row group panel under the main report design area. Choose Add Group -> Parent Group
Choose your Date1 field in the group by drop down . Click OK and you're done.

One to one relationship with foreign key to mutiple tables

Please let me start by saying, I know this has been asked many times before and I've studied other questions (and answers) but after 2 days of reading questions and amending my database I can't get this to work as I want.
At the moment I have various tables, for example customer, supplier, product, banner, etc.
I have a table called custom_field which allows custom fields to be created and used against various other tables.
At the moment some of my tables look like this:
General Tables
==============
Customer
+-------------+---------------+
| customer_id | customer_name |
+-------------+---------------+
| 1 | Peter |
| 2 | Sally |
+-------------+---------------+
Banner
+-----------+-------------+--------------+
| banner_id | banner_name | banner_width |
+-----------+-------------+--------------+
| 1 | Easter | 100px |
| 2 | Xmas | 250px |
+-----------+-------------+--------------+
Tables for managing custom fields
=================================
Custom_Field
+----------+------------+----------------+-----------+
| field_id | field_name | field_label | item_type |
+----------+------------+----------------+-----------+
| 100 | fav_color | Favorite Color | customer |
| 101 | border | Border | banner |
+----------+------------+----------------+-----------+
Custom_Field_Value
+----------+----------+---------+-------------+
| value_id | field_id | item_id | field_value |
+----------+----------+---------+-------------+
| 1567 | 100 | 1 | Red |
| 1568 | 100 | 2 | Blue |
| 1569 | 101 | 1 | Solid |
| 1570 | 101 | 2 | Dotted |
+----------+----------+---------+-------------+
To clarify, item_id refers to a customer_id, a banner_id, or a supplier_id, etc. In the example above this means Peter has a "favorite color" custom field set to Red, and Sally has a "favorite color" custom field set to Blue.
The Easter Banner has a "border" custom field set to solid, and the Xmas Banner has a "border" custom field set to Dotted.
This all works fine, except there can be no foreign key or referential integrity set between Custom_field_value.item_id and Customer.customer_id (or Banner.banner_id) because item_id's context is described by the item_type field in the Custom_Field table.
I don't want to create multiple nullable foreign keys (not sure that would even work anyway) as it will become unmanageable.
I did try creating sub tables, for example customer_custom_field, and relate this between Customer and Custom_Field, but again it becomes unmanageable when you consider every table could potentially have custom fields.
A single field value would only ever apply to a single entity from another table.
As an aside I also want to create an Attachments table for managing uploaded attachments to a particular entity, and again that could apply to customers, suppliers, products and various other tables, so it's a similar issue.

creating a sorted list in database

So basically I have a table named contents where users can store their items. Normally here when a user add a new item, The item is added at the end of rows.
Something like:
|ID | Name | Item |
--------------------
|1 | Jack | pen |
|2 | Mark | apple |
|3 | albert| orange|
|4 | Jack | pencil|
But the problem with above is that it might take a lot of time when we have a lot of users and items like Jack's first item is at row ID 40 and item #2 is at 1000048 and so which might take a while to search for all the items that belongs to Jack So I was wondering how to sort them up by their Name so it could be something like:
|ID | Name | Item |
--------------------
|1 | Jack | pen |
|2 | Jack | pencil|
|3 | Mark | apple |
|4 | albert| orange|
And if the user added a new item it should be added to the end of his rows list.
All replies are much appreciated, Thank:)
Add index(es) for any column (or combination of columns) you want to search for and/or want to order by.
Do not reorder the table, nor re-number the ids.
If you are talking about 1000 rows, you are unlikely to notice any performance problems even if you don't do proper indexing or normalization. With a million rows, you will notice.

Link to multiple foreign rows from one row

I really don't know how this is called so I couldn't find an answer.
For example I have the following tables:
Table products Table users
+----------+----------+----------+ +----------+----------+
| id | name | price | | username | products |
+----------+----------+----------+ +----------+----------+
| 1 | Bread | 1.5 | | James | 1, 2 |
+----------+----------+----------+ +----------+----------+
| 2 | Cookies | 2.0 | | David | 2, 3 |
+----------+----------+----------+ +----------+----------+
| 3 | Milk | 1.2 | | Paul | 3, 1 |
+----------+----------+----------+ +----------+----------+
products.id is the foreign key for users.products.
I would like to get the name and price of all David's products using a MySQL query. This should return the following:
+----------+----------+
| name | price |
+----------+----------+
| Cookies | 2.0 |
+----------+----------+
| Milk | 1.2 |
+----------+----------+
The JOIN function would be the best to use I guess, but David can have just 1 or 100 products. Creating 100 columns to fit all products doesn't sound very efficient.
How can I realize this?
Currently I'm just fetching everything and filter it using PHP, this is not a problem at the moment but as the tables will grow I guess this will be very inefficient.
This could be solved by changing your data model.
users
+----------+----------+
| id | username |
+----------+----------+
| 1 | Fred |
+----------+----------+
| 2 | John |
+----------+----------+
products
+----------+----------+----------+
| id | name | price |
+----------+----------+----------+
| 1 | Bread | 1.5 |
+----------+----------+----------+
| 2 | Cookies | 2.0 |
+----------+----------+----------+
| 3 | Milk | 1.2 |
+----------+----------+----------+
And here comes the magic: You could connect the two tables using a third table:
user_procuct_connections
+----------+----------+------------+
| id | user_id | product_id |
+----------+----------+------------+
| 1 | 1 | 2 | -> Fred has Cookies
+----------+----------+------------+
| 2 | 1 | 3 | -> Fred also has Milk
+----------+----------+------------+
| 3 | 2 | 1 | -> John has Bread
+----------+----------+------------+
If you want a user to be able to own a single product only, then you can remove the id column, an make the user_id and product_id primary key together.
Then when you want to get for example all of Freds products then just
SELECT
*
FROM
products
WHERE
id IN (
SELECT
product_id
FROM
user_procuct_connections
WHERE
user_id = 1
)
You could try this:
SELECT * FROM products pt
where FIND_IN_SET(pt.id,(select us.prices from users us
WHERE us.username = "David"));
Working fiddle: http://sqlfiddle.com/#!2/4f78d/2
The design for the 'Users' table is wrong. Instead of working around this bad design, please change the design.
So effectively, you design could be as such:
Table Products :
ID Name Price
1 Bread 1.5
2 Cookies 2.0
3 Milk 1.2
Table users :
Username Products
James 1
James 2
David 2
David 3
Paul 3
Paul 1
You see, you can have multiple rows for each user i.e.one row for each product in the Users table. You can maintain another Boolean field to identify which ones are currently 'active' or 'applicable'. Joins' would be much easier in that case. Also, updating records would also be easier. In case, in future you'd want to retrieve & analyse data from historic records, that would be possible too!!!
Another thing with the current design is that times and again you'd have to work around the infamous "comma-seperated values". Let's say you have a record as such:
Username Products
James 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
If you need to sort this data into rows, you'd have to work-around the 'Comma-seperated' values so many times. Imagine doing that for 'n' number of records!!
Hope this helps!!!
If you join the tables like:
SELECT name, price FROM products AS p INNER JOIN user_products AS up ON up.id = p.product_id AND up.user_id = <davids id>
You will get an array where first column will be the name and the second the price. You can then do what you want with it in PHP and change the array. You don't have to filter anymore.

Database structure for a classifieds website

I am developing a classifieds website similar to Quickr.com.
The main problem is that each category requires a different set of properties. For example, for a mobile phone the attributes might be Manufacturer, Operating System, Is Touch Screen, Is 3G enabled etc... Whereas for an apartment the attributes are Number of bedrooms, Is furnished, Which floor, total area etc. Since the attributes and the number of attributes varies for each category, I am keeping the attributes and their values in separate tables.
My current database structure is
Table classifieds_ads
This table stores all the ads. One record per ad.
ad_id
ad_title
ad_desc
ad_created_on
cat_id
Sample data
-----------------------------------------------------------------------------------------------
|ad_id | ad_title | ad_desc | ad_created_on | cat_id |
-----------------------------------------------------------------------------------------------
|1 | Nokia Phone | Nokia n97 phone for sale. Excellent condition | <timestamp> | 2 |
-----------------------------------------------------------------------------------------------
Table classifieds_cat
This table stores all the available category. cat_id in classifieds_ads table relates to cat_id in this table.
cat_id
category
parent_cid
Sample data
-------------------------------------------
|cat_id| category | parent_cid |
-------------------------------------------
|1 | Electronics | NULL |
|2 | Mobile Phone | 1 |
|3 | Apartments | NULL |
|4 | Apartments - Sale | 3 |
-------------------------------------------
Table classifieds_attribute
This table contains all the available attributes for a particular category. Relates to classifieds_cat table.
attr_id
cat_id
input_type
attr_label
attr_name
Sample data
-----------------------------------------------------------
|attr_id | cat_id | attr_label | attr_name |
-----------------------------------------------------------
|1 | 2 | Operating System | Operating_System |
|2 | 2 | Is Touch Screen | Touch_Screen |
|3 | 2 | Manufacturer | Manufacturer |
|4 | 3 | Bedrooms | Bedrooms |
|5 | 3 | Total Area | Area |
|6 | 3 | Posted By | Posted_By |
-----------------------------------------------------------
Table classifieds_attr_value
This table stores the attribute value for each ad in classifieds_ads table.
attr_val_id
attr_id
ad_id
attr_val
Sample data
---------------------------------------------
|attr_val_id | attr_id | ad_id | attr_val |
---------------------------------------------
|1 | 1 | 1 | Symbian OS |
|2 | 2 | 1 | 1 |
|3 | 3 | 1 | Nokia |
---------------------------------------------
========
Is this design okay?
Is it possible to index this data with solr?
How can I perform a faceted search on this data?
Does MySQL support field collapsing like solr?
My suggestion is to remove cat_id from the classifieds_attribute table, then create a new table.
The new table would look like:
cat_attr | id | cat_id | attr_id
This should help you decrease redundancy.
Your design is fine, although I question why you are using hierarchical categories. I understand that you want to organize categories from an end-user standpoint. The hierarchy helps them drill down to the category that they are looking for. However, your schema allows for attribute values at every level. I would suggest that you only need (or possibly want) attributes at the leaf level.
It is certainly possible that you could come up with attributes that would be applicable at higher levels, but this would drastically complicate your management of the data since you'd have to spend a lot of time thinking about exactly how high up the chain a certain attribute belongs and whether or not there is some reason why a lower level might be an exception to the parent rule and so forth.
It also certainly over complicates your retrieveal as well - which is part of the reason for your question, I think.
I would suggest creating an additional table that will be used to manage the hierarchy of categories above the leaf level. It would look exactly like your classifieds_cat table except the involuted relationship will obviously be to the new table. Then classifieds_cat.parent_cid becomes an FK to the new table rather than an involuted FK to classifieds_cat.
I think this schema change will reduce your application and data management complexity.