简体   繁体   English

MySQL SELECT WHERE OR-仅当第二行为空时才选择一行

[英]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: 所以问题是:

  1. 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. 这正是我所需要的,但需要了解为什么它会以这种方式工作。

  2. 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM