[英]MySQL SELECT WHERE OR - pick one line only if second is empty
I'm joining 2 tables, for example 例如,我要加入2张桌子
PRODUCTS (PRODUCT_ID, NAME)
and 和
PRICE_LEVELS (PRODUCT_ID, PRICE, PRICE_LVL_NAME )
(ofc. it's simplified, there is several joins ). (ofc。它是简化的,有多个join)。
in the PRICE_LEVELS
table, I have some possibilities of price level names, let's say " DEFAULT " and LEVEL1, so we ended up with something like: 在
PRICE_LEVELS
表中,我有一些价格级别名称的可能性,比如说“ DEFAULT ”和“ LEVEL1”,因此最终得到了以下内容:
PRODUCT_ID | PRICE | PRICE_LVL_NAME
1 | 100 | _DEFAULT_
1 | 50 | LEVEL1
2 | 130 | _DEFAULT_
Both tables are joined in the view. 这两个表都在视图中联接。
What I need is to get price, but only once - I mean if there is LEVEL1 defined, pick that one, otherwise pick DEFAULT. 我需要的是获取价格,但只能获取一次-我的意思是,如果定义了LEVEL1,则选择该价格,否则选择DEFAULT。
Meantime, I have used GROUP BY and thing seems to work, but I have no idea why (ofc. I've used a lot of test data and it's simply always works, but not sure, how it's reliable). 同时,我使用了GROUP BY,但事情似乎仍然有效,但我不知道为什么(官方。我使用了很多测试数据,它始终可以正常工作,但不确定其可靠性如何)。
Let's say our view (combining both tables) has name V_PRODUCTS, so I'm running query: 假设我们的视图(合并两个表)的名称为V_PRODUCTS,因此我正在运行查询:
SELECT *
FROM `V_PRODUCTS`
WHERE (PRICE_LVL_NAME = '_DEFAULT_' OR PRICE_LVL_NAME = 'LEVEL1')
GROUP BY `PRODUCT_ID `;
So the questions are: 所以问题是:
Why the query above works ? 为什么上面的查询有效? GROUP BY is always choosing LEVEL1, if is available and DEFAULT if not.
GROUP BY总是选择LEVEL1(如果可用),而选择DEFAULT(如果没有)。 It's exactly what I need, but need to understand why it's working this way.
这正是我所需要的,但需要了解为什么它会以这种方式工作。
Is there any way how to do this more explicit in the SQL ? 有什么办法可以在SQL中更明确地做到这一点?
UPDATE: there is unlimited number of possible levels 更新:可能的级别数量不限
Q1: It's not reliable, it's probably based on internal storage and might change at any time. Q1:它不可靠,它可能基于内部存储,并且可能随时更改。
Q2: Join the table twice using an Outer Join and return the best match using COALESCE: Q2:使用外部联接联接表两次,并使用COALESCE返回最佳匹配项:
SELECT ..., COALESCE(pl1.PRICE, pl2.PRICE)
FROM `V_PRODUCTS` as p
LEFT JOIN PRICE_LEVELS as pl1
ON p.PRODUCT_ID = pl1.PRODUCT_ID
and PRICE_LVL_NAME = 'LEVEL1')
LEFT JOIN PRICE_LEVELS as ply
ON p.PRODUCT_ID = pl2.PRODUCT_ID
and PRICE_LVL_NAME = '_DEFAULT_'
I don't have a MySQL to play with right now but you should only have to replace the IS NULL part of this MSSQL to make it work I think. 我现在没有MySQL可使用,但您只需要替换此MSSQL的IS NULL部分即可使其正常工作。
If you don't need AlphaNum in the levels or can add a level field that is INT where 0 is default and then 1 and so on, you can join the levels to itself to get the max available level to join to the product table. 如果您在级别中不需要AlphaNum或可以添加一个INT级别字段,其中默认值为0,然后为1,依此类推,则可以将级别自身连接起来以获取可加入产品表的最大可用级别。
SELECT PRODUCTS.*, PriceLvl.*
FROM [PRODUCTS] LEFT JOIN
(SELECT p1.*
FROM PRICE_LEVELS p1
LEFT JOIN PRICE_LEVELS p2 ON
(p1.PRODUCT_ID = p2.PRODUCT_ID
AND p2.PRICE_LVL > p1.PRICE_LVL)
WHERE p2.PRICE_LVL IS NULL) PriceLvl
ON PRODUCTS.PRODUCT_ID = PriceLvl.PRODUCT_ID
That takes 那需要
PRODUCT_ID NAME
1 Tshirts
2 Pants
and 和
PRODUCT_ID PRICE PRICE_LVL
1 10.00 0
1 15.00 1
2 40.00 0
1 20.00 2
and gives 并给
PRODUCT_ID NAME PRODUCT_ID PRICE PRICE_LVL
1 Tshirts 1 20.00 2
2 Pants 2 40.00 0
I'd assign a numeric value for each level with zero for default, and store it same table. 我会为每个级别分配一个默认值为零的数值,并将其存储在同一张表中。
select t1.price from price_levels t1
where t1.product_id = @X and price_level = (select max(price_level)
from price_levels t2 where t1.product_id = t2.product_id)
WHERE price_level IN ('_DEFAULT_', 'mylevel')
ORDER BY
price_level = '_DEFAULT_'
LIMIT 1
The WHERE
will grab 1 or 2 rows. WHERE
将抓取1或2行。
price_level = '_DEFAULT_'
will be 1 for default, otherwise 0. 0 sorts before 1. So, if there is a 'mylevel', it will come first. price_level = '_DEFAULT_'
默认为1,否则为0。0在1之前排序。因此,如果存在'mylevel',它将排在第一位。
LIMIT 1
says to pick the first (or only) row. LIMIT 1
说选择第一行(或唯一行)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.