I’m trying to figure out how to set a column to true when other columns from the query be true.
I have two tables called products and families. A family can have a lot of products and a product can have a main product.
When I execute my select, I should:
- All products that don’t have a family
- All products that have a family
- All products that have a family and is a main product (if the product is main product, i don’t need to recover others product from this family, only the main product)
My problem is that a have a column called product_launch and it’s easy to recover when the product came separately. So I’m trying to set a field of the main product that returns in my query a following rule: If any product of this family has a flag product_launch as true I should set the main product product_launch column to true even if the main product is false.
In this fiddle I have an example that I’m trying to do.
I already tried using any, over/window, and aggregate functions but nothing was able to reach my objective.
My goal at the end of this example is to return for example Playstation 3 with product_launch as true because it’s a main product and PlayStation 5 which is in the same family has product_launch true. In the other cases, it’s already working because it brings separately.
In this example I have the following rules:
- Pepsi and Cocacola should return because they dont have family.
- Macbook 2015 and macbook 2018 belogs to family (Macbooks) but any of them is a main product so I should receive them in select.
- Family Consoles the only product that could return is playstation 3 because it is main product from Family Consoles. But it need to change the flag product_launch to true because in family (Consoles) there is a product (Playstation 5) that have this flag true.
If I have some product in family that have flag product_launch as true I should return main product with this flag true even if the main product has flag product_launch as false.
Hope someone can help me to know what to do in Postgresql to reach this goal. Thanks!
3
Answers
I’m not sure, if this is want you want to get, but try this:
I’m not sure I fully understand what you want. I added a "playstation 4" row that’s not the main_product, so its
product_launch
value is not changed. If this isn’t what you want the other answers are probably easier.Query #1
View on DB Fiddle
Edit:
Updating the answer to remove unwanted rows from the final select:
There are some issues with the original table design. The most troublesome is that families and products are mutually referential. The foreign key association from families to products is not declared in the DDL, but is evident in the query. Among the problems caused by this design is the inability to use constraints to ensure that families.main_product_id and products.family_id are mutually consistent. I’ve refactored the tables by removing main_product_id from families and adding a boolean flag, is_main_product, to products. A partial unique index enforces the constraint that each family can have only one main product.
I’ve also made the following changes that aren’t relevant to the original problem, but improve the model:
NOT NULL
with defaults.The changes to the boolean columns help to avoid additional complexity related to handling
NULL
s when evaluating logic expressions.Here are the revised table creation statements:
Please note, there is an issue caused by using an index to enforce the rule that a family can have only one main product: changing the main product requires two updates, one to set is_main_product to false for the current main product, and a second to set is_main_product to true for the new main product. Since both updates can occur within the same transaction, this should be a minor inconvenience.
I reworked the inserts to eliminate explicit dependencies on generated id values. This helps ensure that id values and the associated sequences are synchronized.
The following query returns output consistent with the sample posted in the original question: