简体   繁体   English

CASE WHEN PostgreSQL 仅适用于一种情况

[英]CASE WHEN PostgreSQL only working for one case

I'm writing a query that will go into some golang backend code to autopopulate some billing fields that we have.我正在编写一个查询,该查询将进入一些 golang 后端代码以自动填充我们拥有的一些计费字段。 Basically there's a standard fee and a reduced fee.基本上有标准费用和减免费用。 There's a table of these fees, the ID number, and the effective date.有这些费用、ID 号和生效日期的表格。

If the ID number is in the list, I want to just select the fee for that ID number.如果 ID 号在列表中,我只想选择该 ID 号的费用。 If the ID number is not in the list, I want to select the standard fee.如果身份证号码不在列表中,我想选择标准费用。

On the statements we get, we are given the MemberID.在我们得到的语句中,我们得到了 MemberID。 The MemberID joins with a CorporateID (CorpID) in a CorporateLinks table. MemberID 与 CorporateLinks 表中的 CorporateID (CorpID) 连接。 If the MemberID is not in the CorporateLinks table at all, I want to select the standard fee.如果 MemberID 根本不在CorporateLinks 表中,我想选择标准费用。

Here is my query:这是我的查询:

SELECT
CASE
WHEN cl.CorpID IN (SELECT CorpID FROM ConversionFactor) THEN MAX(cf.ConversionFactor)
WHEN MemberID NOT IN (SELECT MemberID FROM CorporateLinks) THEN MAX(cf.ConversionFactor)
ELSE MAX(cf.ConversionFactor) 
END 
FROM ConversionFactor cf
LEFT JOIN CorporateLinks cl
ON cf.CorpID = cl.CorpID
WHERE EffectiveDate = (SELECT EffectiveDate FROM ConversionFactor
                       WHERE EffectiveDate < $2
                       ORDER BY EffectiveDate DESC LIMIT 1)
AND MemberID = $1
GROUP BY cl.CorpID, cl.MemberID;

When the MemberID maps to a CorpID and the CorpID is in the list, it returns it perfectly.当 MemberID 映射到 CorpID 并且 CorpID 在列表中时,它会完美地返回它。 When the MemberID is NOT in CorporateLinks, it returns an empty field.当 MemberID 不在 CorporateLinks 中时,它返回一个空字段。 I haven't found a test case where the MemberID is in CorporateLinks but CorpID is not in ConversionFactor ( ELSE Case).我还没有找到一个测试用例,其中 MemberID 在 CorporateLinks 中,但 CorpID 不在 ConversionFactor ( ELSE Case) 中。

I'm not sure where I'm going wrong.我不确定我哪里出错了。 I'm not very well versed in using CASE WHEN statements in queries, I've only used them in functions before to perform regex operations.我不是很精通在查询中使用 CASE WHEN 语句,我之前只在函数中使用它们来执行正则表达式操作。

There are several questionable things about your query.您的查询有几个值得怀疑的地方。

The parts relevant to the discussion look like:与讨论相关的部分如下所示:

SELECT CASE WHEN ... IN (SELECT ...)
            THEN conversionfactor
            WHEN ... NOT IN (SELECT ...)
            THEN max(conversionfactor)
            ELSE max(conversionfactor)
       END
FROM ...
GROUP BY ..., conversionfactor, ...;

Observations:观察:

  1. There can be only a single value of conversionfactor in each group, because that column is part of the GROUP BY clause.只能有单一值conversionfactor每个组中,因为该列是一部分GROUP BY子句。

    So it makes no sense to write max(conversionfactor) - it is going to be the same as conversionfactor .因此,它是没有意义的写max(conversionfactor) -这将是一样conversionfactor

  2. The second THEN branch and the ELSE branch both return max(conversionfactor) , so the second WHEN clause is superfluous.第二个THEN分支和ELSE分支都返回max(conversionfactor) ,因此第二个WHEN子句是多余的。

Since all three branches return the same value, the whole CASE expression can be replaced with conversionfactor , because that is always going to be the result.由于所有三个分支都返回相同的值,因此可以将整个CASE表达式替换为conversionfactor ,因为这始终是结果。

But your actual question is why the CASE expression returns an "empty field".但您的实际问题是为什么CASE表达式返回“空字段”。

From the above discussion that would mean that conversionfactor is either an empty string (if it is a string type) or NULL.从上面的讨论中可以看出, conversionfactor要么是一个空字符串(如果它是一个字符串类型)要么是 NULL。

Now there is no reason why this shouldn't be the case.现在没有理由不应该是这种情况。 You have to examine your data and look for NULL values or empty strings in that column.您必须检查您的数据并在该列中查找 NULL 值或空字符串。 The CASE expression is useless, but it is not at fault for that. CASE表达式是无用的,但它并没有错。

You want to use a LEFT JOIN .您想使用LEFT JOIN The default join type if you don't specify is an INNER JOIN , and so if there is no entry in ConversionFactor that matches, the result set will omit it completely, not just set the relevant column(s) to NULL .如果未指定,默认连接类型是INNER JOIN ,因此如果ConversionFactor中没有匹配的条目,结果集将完全忽略它,而不仅仅是将相关列设置为NULL Also your WHERE clause explicitly filters for MemberId .此外,您的WHERE子句显式过滤MemberId If MemberId is NULL , you'll never see any results as a result either.如果MemberIdNULL ,您也永远不会看到任何结果。

You are also using sub-selects when it's not clear you need them.当不清楚您需要它们时,您也会使用子选择。 Once you switch to the LEFT JOIN see what the output looks like with a simple selection:切换到LEFT JOIN ,通过简单的选择查看输出结果:

SELECT cf.*, cl.*
FROM ConversionFactor cf
  LEFT JOIN CorporateLinks cl USING (CorpID)
WHERE cf.EffectiveDate < $2
LIMIT 100 -- Limit for a sanity check to prevent too many results as you debug

Once you can see your whole result set, it should be easier to work out how you want to filter and aggregate later by editing which columns you want returned.一旦您可以看到整个结果集,通过编辑要返回的列来确定以后要如何过滤和聚合应该会更容易。

It's quite possible that you don't need the CASE statement at all.您很可能根本不需要CASE语句。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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