苦苦挣扎的SQL Where过滤器

时间:2015-05-15 13:20:18

标签: sql sql-server

我有一个表[Customer],它有[postcode]和[totalValue]字段。

我需要设计一个查询,它返回所有[postcode]的前两个字符,然后是该特定邮政编码组的[totalValue]的SUM(因此NW,L1等各有一个值)。< / p>

我有这个代码,运行正常:

SELECT LEFT(postcode, 2), SUM(totalValue)
  FROM Customer
  GROUP BY LEFT(postcode, 2)

...但是,[客户]中的条目不包含有效的[邮政编码]。

有效的英国邮政编码总是一个或两个字母后跟一个数字(例如LE1,L12等)。

我想将所有不正确/空/ Null [邮政编码]记录过滤到单独的记录条目中,但这超出了我的技能。

6 个答案:

答案 0 :(得分:5)

您可以使用LIKE

where postcode like '[A-Z][A-Z0-9][0-9]%'

您可能还想检查长度和其他特征,但这可以回答您的具体问题。

编辑:

要获得单独的条目,请使用case

SELECT (CASE WHEN postcode like '[A-Z][A-Z0-9][0-9]%'
             THEN LEFT(postcode, 2)
             ELSE 'Separate Entry'
        END) as PostCode2, SUM(totalValue)
FROM Customer
GROUP BY (CASE WHEN postcode like '[A-Z][A-Z0-9][0-9]%'
               THEN LEFT(postcode, 2)
               ELSE 'Separate Entry'
          END);

答案 1 :(得分:1)

您对有效邮政编码的假设略有不足

  

有效的英国邮政编码总是一个或两个字母后跟一个数字(例如LE1,L12等)。

最简单的说法是valid formats for a UK Postcode

+----------+---------------------------------------------+----------+
| Format   |               Coverage                      | Example  |
+----------+---------------------------------------------+----------+
| AA9A 9AA | WC postcode area; EC1–EC4, NW1W, SE1P, SW1  | EC1A 1BB |
+----------+---------------------------------------------+----------+
| A9A 9AA  | E1W, N1C, N1P                               | W1A 0AX  |
+----------+---------------------------------------------+----------+
| A9 9AA   | B, E, G, L, M, N, S, W                      | M1 1AE   |
| A99 9AA  |                                             | B33 8TH  |
+----------+---------------------------------------------+----------+
| AA9 9AA  |    All other postcodes                      | CR2 6XH  |
| AA99 9AA |                                             | DN55 1PT |
+----------+---------------------------------------------+----------+

您可以为每个模式匹配:

AA9A 9AA - [A-Z][A-Z][0-9][A-Z] [0-9][A-Z][A-Z]
A9A 9AA  - [A-Z][0-9][A-Z] [0-9][A-Z][A-Z]
A9 9AA   - [A-Z][0-9] [0-9][A-Z][A-Z]
A99 9AA  - [A-Z][0-9][0-9] [0-9][A-Z][A-Z]
AA9 9AA  - [A-Z][A-Z][0-9] [0-9][A-Z][A-Z]
AA99 9AA - [A-Z][A-Z][0-9][0-9] [0-9][A-Z][A-Z]

对于可重复使用的东西,我认为值得存储,所以我会为它创建一个表:

CREATE TABLE dbo.SimplePostCodeValidation
(
    PostCode VARCHAR(8) NOT NULL,
    Pattern VARCHAR(50) NOT NULL
);
INSERT dbo.SimplePostCodeValidation (PostCode, Pattern)
VALUES
    ('AA9A 9AA', '[A-Z][A-Z][0-9][A-Z] [0-9][A-Z][A-Z]'),
    ('A9A 9AA', '[A-Z][0-9][A-Z] [0-9][A-Z][A-Z]'),
    ('A9 9AA', '[A-Z][0-9] [0-9][A-Z][A-Z]'),
    ('A99 9AA', '[A-Z][0-9][0-9] [0-9][A-Z][A-Z]'),
    ('AA9 9AA', '[A-Z][A-Z][0-9] [0-9][A-Z][A-Z]'),
    ('AA99 9AA', '[A-Z][A-Z][0-9][0-9][0-9][A-Z][A-Z]'),
    -- REPEAT THE POSTCODES WITHOUT SPACES
    ('AA9A9AA', '[A-Z][A-Z][0-9][A-Z][0-9][A-Z][A-Z]'),
    ('A9A9AA', '[A-Z][0-9][A-Z][0-9][A-Z][A-Z]'),
    ('A99AA', '[A-Z][0-9][0-9][A-Z][A-Z]'),
    ('A999AA', '[A-Z][0-9][0-9][0-9][A-Z][A-Z]'),
    ('AA99AA', '[A-Z][A-Z][0-9][0-9][A-Z][A-Z]'),
    ('AA999AA', '[A-Z][A-Z][0-9][0-9][0-9][A-Z][A-Z]');

现在您可以轻松验证您的邮政编码:

DECLARE @T TABLE (Postcode VARCHAR(8));
INSERT @T (PostCode)
SELECT PostCode
FROM dbo.SimplePostCodeValidation
UNION ALL
SELECT  PostCode
FROM    (VALUES ('123456'), (''), ('TEST')) t (PostCode);

SELECT  t.PostCode, IsValid = CASE WHEN pc.PostCode IS NULL THEN 0 ELSE 1 END
FROM    @T AS t
        LEFT JOIN SimplePostCodeValidation AS pc
            ON t.PostCode LIKE pc.Pattern;

返回:

PostCode    IsValid
----------------------
AA9A 9AA    1
A9A 9AA     1
A9 9AA      1
A99 9AA     1
AA9 9AA     1
AA99 9AA    1
123456      0
            0
TEST        0

要将此应用于您的情况,您可以使用:

SELECT  CASE WHEN pc.PostCode IS NULL THEN 'Invalid' ELSE LEFT(c.postcode, 2) END, 
        TotalValue = SUM(totalValue)
FROM    Customer AS c
        LEFT JOIN SimplePostCodeValidation AS pc
            ON t.PostCode LIKE pc.Pattern;
GROUP BY CASE WHEN pc.PostCode IS NULL THEN 'Invalid' ELSE LEFT(c.postcode, 2) END;

如果您想要变得更复杂,实际上有效的邮政编码存在进一步的限制,例如:如果是模式A9 9AA则第一个字母只能是(B,E,G,L,M,N,S,W)中的一个。该指南载于维基百科州:

  • 只有一位数地区的区域:BR,FY,HA,HD,HG,HR,HS,HX,JE,LD,SM,SR,WC,WN,ZE(尽管WC总是被另一个字母细分) ,例如WC1A)。
  • 只有两位数区域的区域:AB,LL,SO。
  • 有区的区域&#39; 0&#39; (零):BL,BS,CM,CR,FY,HA,PR,SL,SS(BS是唯一同时拥有0区和10区的区域。)
  • 以下伦敦市中心的单位数区域通过在数字后面和空格前插入一个字母进一步划分:EC1-EC4(但不是EC50),SW1,W1,WC1,WC2和E1的一部分(E1W) ),N1(N1C和N1P),NW1(NW1W)和SE1(SE1P)。
  • 字母QVX未在第一个位置使用。
  • 字母IJZ未在第二位使用。
  • 当结构以A9A开头时,出现在第三个位置的唯一字母是ABCDEFGHJKPSTUW。
  • 当结构以AA9A开头时,第四个位置出现的唯一字母是ABEHMNPRVWXY。
  • 最后两个字母不使用字母CIKMOV,以免在手写时形成数字或彼此。
  • 邮政编码扇区是十位数之一:0到9只有一次只使用了一次9在邮政城镇使用,除了克罗伊登和纽波特(见上文)。

由于SQL Server不支持完整的正则表达式,因此考虑到所有这些警告会更加复杂。如果您真的想要进行傻瓜证明验证,我倾向于使用answers this question中的正则表达式,并使用CLR函数来验证邮政编码。

答案 2 :(得分:0)

试试这个。所有不正确(或NULL)的邮政编码都将在“ - ”条目中累积:

SELECT 
  CASE 
    WHEN postcode like '[A-Z][A-Z0-9][0-9]%'
    THEN LEFT(postcode, 2)
    ELSE '--'
  END, 
  SUM(totalValue)
FROM Customer
GROUP BY 
  CASE 
    WHEN postcode like '[A-Z][A-Z0-9][0-9]%'
    THEN LEFT(postcode, 2)
    ELSE '--'
  END

答案 3 :(得分:0)

查询:

border-collapse

使用WITH CTE AS (SELECT CASE WHEN postcode LIKE('[A-Z][A-Z0-9][0-9]%') THEN LEFT(postcode,2) ELSE 'Invalid' END AS PostCode ,totalValue FROM Customer) SELECT PostCode, SUM(totalValue) as totalValue FROM CTE GROUP BY PostCode 收集数据。无效的邮政编码将被归为“无效”。

答案 4 :(得分:-1)

试试这个..

SELECT LEFT(postcode, 2), SUM(totalValue)
  FROM Customer
WHERE ISNUMERIC(LEFT(postcode, 1))<> 1
GROUP BY LEFT(postcode, 2)

希望这有帮助。

答案 5 :(得分:-2)

这是选择:

SELECT LEFT(postcode, 2), SUM(totalValue)
FROM Customer
WHERE postcode IS NOT NULL AND postcode != '' AND dbo.fn_isValid(postcode) = 1
GROUP BY LEFT(postcode, 2)
UNION
SELECT 'NULL', SUM(totalValue)
FROM Customer
WHERE postcode IS NULL
GROUP BY LEFT(postcode, 2)
UNION 
SELECT 'EMPTY', SUM(totalValue)
FROM Customer
WHERE postcode = ''
GROUP BY LEFT(postcode, 2)
UNION
SELECT 'WRONG', SUM(totalValue)
FROM Customer
WHERE dbo.fn_isValid(postcode) = 0
GROUP BY LEFT(postcode, 2)

然后你需要评估函数,如下所示:

CREATE FUNCTION [dbo].[fn_IsValid]
    (
    @Code nchar(32)
    )
RETURNS bit
AS
BEGIN
DECLARE @Status bit

SET @Status = -- Your validation logic
--be aware of empty and null values

RETURN @Status
END