I want to show data that a user can modify. If the user do changes, i like keeping the original data in my database.
When a user get data, he should view the data modified.
(Much users can modiffied data).
For example:
Products (non editable for users)
ID | Name | Color
----------------------
1 | Apples | Yellow
2 | Pears | Green
3 | Lemons | Yellow
ModProducts (one row for modified product and user)
SourceID | UserID | Name | Color
-------------------------------------------
1 | 3 | RedApples | Red
1 | 4 | Sminth Apples | Green
Result for UserID 3:
ID | Name | Color
-------------------------
1 | RedApples | Red
2 | Pears | Green
3 | Lemons | Yellow
I tryed with COALESCE, CASE but i canĀ“t filter by UserID.
I Also tryed with GROUP BY, putting all data in same table, but I have not managed to give priority to the modified data
I'm going crazy..
Maybe you're designing the data model wrong?
You probably just misplaced the UserID filter. The filter on UserID has to be part of the outer join condition it can not be in the where clause. Try the following select:
select p.id,
coalesce(m.name, p.name) name,
coalesce(m.color, p.color) color
from products p
left join modproducts m on m.id = p.id and
m.userid = 3
Problem solved in one table
Table Products
ID | Ref | UserID | Name | Color
-------------------------------------------
1 | 1 | 0 | Apples | Yellow
2 | 2 | 0 | Strawberrys | Red
3 | 3 | 0 | Lemons | Yellow
4 | 1 | 2 | Apples | Green
5 | 1 | 3 | MiniApples | Green
I like this result
ID | Ref | UserID | Name | Color
-------------------------------------------
4 | 1 | 2 | Apples | Green
2 | 2 | 0 | Strawberrys | Red
3 | 3 | 0 | Lemons | Yellow
I resolv this form:
SELECT *
FROM ( SELECT * FROM Products ORDER BY Ref, UserID DESC) AS Prod
WHERE UserID = 2
OR UserID = 0
GROUP BY Ref
Related
I have a table that has the relations of products and colors. Each product has one or multiple colors. Is it possible to do a query that returns only the products that have one color only and the color wanted ?
Value from the api : color_slug = white ;
Sample table :
color_table
+----------+------------+
| color_id | color_slug |
+----------+------------+
| 1 | white |
| 2 | blue |
| 3 | black |
| 4 | green |
| 5 | red |
| 6 | yellow |
+----------+------------+
product_table
+------------+--------------+
| product_id | product_name |
+------------+--------------+
| 1 | shoes |
| 2 | shorts |
| 3 | t-shirt |
| 4 | jacket |
| 5 | watch |
| 6 | glasses |
+------------+--------------+
pc_relation
+----+------------+----------+
| id | product_id | color_id |
+----+------------+----------+
| 1 | 1 | 5 |
| 2 | 1 | 1 |
| 3 | 2 | 1 |
| 4 | 2 | 4 |
| 5 | 2 | 3 |
| 6 | 3 | 2 |
| 7 | 4 | 1 |
| 8 | 5 | 5 |
| 9 | 5 | 6 |
| 10 | 6 | 1 |
+----+------------+----------+
Select unique color values (if i put WHERE color_id = 1 the product colors are not longer of one color only) :
SELECT product_id
FROM pc_relation
// WHERE color_id = 1
GROUP BY product_id
HAVING MIN(color_id) = MAX(color_id)
pc_relation.id = 6,7,10
SELECT *
FROM color_table
INNER JOIN pc_relation ON pc_relation.color_id = color_table.color_id
INNER JOIN product_table ON pc_relation.product_id = product_table.product_id
WHERE colors.color_slug = 'white'
Values wanted (color_slug = white):
pc_relation.id = 7,10
product_table.product_name = jacket, glasses
*all the combinations are unique and indexed. For example I cannot have one product with the same color
twice.
You are on the right track with your first query. Move the color comparison to the HAVING clause:
SELECT product_id
FROM pc_relation
GROUP BY product_id
HAVING MIN(color_id) = MAX(color_id) AND
MIN(color_id) = 1;
You can also phrase this using NOT EXISTS:
select r.*
from pc_relation r
where r.color_id = 1 and
not exists (select 1
from pc_relation r2
where r2.product_id = r.product_id and r2.color_id <> r.color_id
);
However, the GROUP BY method is more general.
Here is a table structure example:
// tablename
+----+------+---------+
| id | numb | color |
+----+------+---------+
| 1 | 4 | green |
| 2 | 4 | yellow |
| 3 | 3 | red |
+----+------+---------+
Here is a query example:
SELECT id, numb, color FROM tablename ORDER BY numb asc
The result will be:
+----+------+---------+
| id | numb | color |
+----+------+---------+
| 3 | 3 | red |
| 1 | 4 | green |
| 2 | 4 | yellow |
+----+------+---------+
Now, my focus is on the order of these rows:
| 3 | 4 | green |
| 2 | 4 | yellow |
Because their numb values are equal, Now I want to know, for several executing that query, they will be constant? (Is order guaranteed for the identical values?) Or there isn't any guarantee and I should use another column name in the query like this ORDER BY numb, id asc ?
Short answer: No, there is no guarantee. (as #Strawberry wrote under the question)
Full answer: You can add a new column named sort_identical, And fill it whatever you like. And then use this:
... ORDER BY numb, sort_identical asc
(Also you can use id instead of creating a new column - But if you need to sort it differently than id, then create a new column)
+----+------+---------+----------------+
| id | numb | color | sort_identical |
+----+------+---------+----------------+
| 3 | 3 | red | 1 |
| 1 | 4 | green | 2 |
| 2 | 4 | yellow | 3 |
+----+------+---------+----------------+
Table Definitions
Table 1 (horizontal) This is a table of users
| id | name | phone |
---------------------
| 1 | Bob | 800 |
| 2 | Phil | 800 |
Table 2 (Vertical Table) This is a table of teams
| id | name |
------------------
| 1 | Donkey |
| 2 | Cat |
Table 3 (Vertical Table) This table is connecting the first two
| id | user_id | team_id |
--------------------------
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 1 |
My Goal
I would like to be able to query the data in such a way that i get the following back:
| id | name | phone | Donkey | Cat |
-------------------------------------
| 1 | Bob | 800 | 1 | 1 |
| 2 | Phil | 800 | 1 | Null |
This table would have my horizontal table data, then a combination of the other two vertical tables to create the appended columns. Where table 2 ends up being the column name headings. And the row valus are pulled from table three as a boolean.
You're chasing a pivot table:
select u.*,
sum(case when t1.name = 'Donkey' then 1 else 0 end) Donkey,
sum(case when t1.name = 'Cat' then 1 else 0 end) Cat
from users u
inner join user_team ut1
on u.id = ut1.user_id
inner join teams t1
on ut1.team_id = t1.id
group by name
demo: http://sqlfiddle.com/#!9/5fd33/7
I want to make merge 2 tables, and then do ORDER BY, first to order them by top column, so that products with value 1 in top show up first in record set.
Afterwards, I want to order them by premium column, so that products with value 1 go right after top products.
After that, I want the rest of products to order by pub_date from table items, and products with value 1 in column highlighted should not be shown directly bellow top and premium items.
Since original tables are full of unnecessary info, here's the stripped down versions:
Table `items`:
+-------+------------+--------+
| pk_id | pub_date | author |
+-------+------------+--------+
| 1 | 2013-06-11 | John |
| 2 | 2013-06-12 | Mike |
| 3 | 2013-06-25 | Seth |
| 4 | 2013-06-11 | Drew |
| 5 | 2013-06-13 | Joe |
+-------+------------+--------+
Table `paid_items`:
+-------+-----+---------+-------------+--------+
| fk_id | top | premium | highlighted | active |
+-------+-----+---------+-------------+--------+
| 2 | 1 | 0 | 0 | 1 |
| 3 | 0 | 0 | 1 | 1 |
| 4 | 0 | 1 | 0 | 1 |
| 5 | 0 | 0 | 1 | 1 |
+-------+-----+---------+-------------+--------+
EDIT:
Here's the pseudo (or whatever) of what I want to accomplish:
PRODUCTS_LIST>
PRODUCTS WITH TOP VALUE
PRODUCTS WITH PREMIUM VALUE
PRODUCTS ORDERED BY PUB_DATE>
PRODUCT WITH NO HIGHLIGHTED VALUE
PRODUCT WITH NO HIGHLIGHTED VALUE
PRODUCT WITH HIGHLIGHTED VALUE
PRODUCT WITH NO HIGHLIGHTED VALUE
PRODUCT WITH HIGHLIGHTED VALUE
...
A striped down version of how the recordset should look like, focus is on highlighted column:
mysql> select pk_id, highlighted from items left join paid_items on items.pk_id
= paid_items.fk_id order by pub_date desc;
+-------+-------------+
| pk_id | highlighted |
+-------+-------------+
| 3 | 1 |
| 5 | 1 |
| 2 | 0 |
| 1 | NULL |
| 4 | 0 |
+-------+-------------+
Simple select would be:-
SELECT *
FROM items a
LEFT OUTER JOIN paid_items b
ON a.pk_id = b.fk_id
ORDER BY b.top, b.premium, a.pub_date
but I presume you know that already.
However I am unsure what you mean by products with value 1 in column highlighted should not be shown directly bellow top and premium items . Do you want these excluded, or displayed at the bottom of the list. Could you put some example output in your question?
I'm currently redesign a heavy loaded website, and I would appreciate any opinion about a specific database design issue.
The concept is to keep in the db a number of products (500K of them).
Every product can have a number of dynamic properties (around 1K), and every property a number of predefined but dynamic values (lets say 10 on average for every property, so around 10K)
At this point of time this is the simplified db structure:
Products (Products Table)
+--------+--------------+
| ProdID | Product Name |
+--------+--------------+
| 1 | T-Shirt XYZ |
+--------+--------------+
| 2 | Dress ABC |
+--------+--------------+
| ... | ... |
+--------+--------------+
| 500000 | Something |
+--------+--------------+
Properties Definition (Props Table) (it holds the Property Types)
+--------+--------------+
| PropID | Property Name|
+--------+--------------+
| 1 | color |
+--------+--------------+
| 2 | size |
+--------+--------------+
| ... | ... |
+--------+--------------+
| 100 | Some Prop |
+--------+--------------+
Properties Values Definition (Values Table)
+-----------+--------+-------+
| PropValID | PropID | Value |
+-----------+--------+-------+
| 1 | 1 | red |
+-----------+--------+-------+
| 2 | 1 | blue |
+-----------+--------+-------+
| 3 | 2 | m |
+-----------+--------+-------+
| 4 | 2 | xl |
+-----------+--------+-------+
| 5 | 2 | xxl |
+-----------+--------+-------+
| ... | ... | ... |
+-----------+--------+-------+
| 1000 | 100 | xyz |
+-----------+--------+-------+
This way we can add any number of properties and values in any product.
The table below holds this info.
Product Properties & Values (ProdPropVal Table)
+--------+--------+--------+-----------+
| InfoID | ProdID | PropID | PropValID |
+--------+--------+--------+-----------+
| 1 | 1 | 1 | 1 |
+--------+--------+--------+-----------+
| 2 | 1 | 2 | 3 |
+--------+--------+--------+-----------+
| 3 | 2 | 1 | 2 |
+--------+--------+--------+-----------+
| 4 | 2 | 2 | 5 |
+--------+--------+--------+-----------+
| ... | ... | ... | |
+--------+--------+--------+-----------+
In the example above we know that "T-Shirt XYZ" has blue color and its size is medium.
And now the tricky part...
if we want to find all products that have a common property values set (all products of blue color and medium size) which is the best approach?
My ideas:
Search one time the ProdPropVal Table for each PropValID and compare the results in code. This can be fine tuned by starting from the most rare PropValIDs and limiting ProdIDs using a WHERE ProdID IN (previous IDs) in the next queries.
Use an Inner Join in the ProdPropVal Table for each PropValID wanted. Something like: SELECT ProdID FROM ProdPropVal ppv1 INNER JOIN ProdPropVal ppv2 ON ppv1.ProdID = ppv2.ProdID INNER JOIN ProdPropVal ppv3 ON ppv1.ProdID = ppv3.ProdID INNER JOIN ProdPropVal ppv4 ON ppv1.ProdID = ppv4.ProdID WHERE ppv1.PropValID = 10 AND ppv2.PropValID = 20 AND ppv3.PropValID = 30 AND ppv4.PropValID = 150
These are my ideas so far. The fact that ProdPropVal tablet has some millions rows doesn't leave any room for error.
Any suggestion is most welcomed!
To find all products with blue colour and medium size I would do this:
SELECT ProdID
FROM ProdPropVal
WHERE (PropID = 1 AND PropValID = 2)
OR (PropID = 2 AND PropValID = 3)
GROUP BY ProdID
HAVING COUNT(*) = 2
Better still, if PropValID is unique in the Values table, then you would remove the PropID column from the ProdPropVal table, and simplify the query to this:
SELECT ProdID
FROM ProdPropVal
WHERE PropValID IN (2, 3)
GROUP BY ProdID
HAVING COUNT(*) = 2