简体   繁体   English

验证帐号SQL表

[英]Validate account number SQL table

I'd like to select data from a table with the following rule, but I'm having trouble writing the query. 我想使用以下规则从表中选择数据,但是在编写查询时遇到了麻烦。 I'm using PostgreSQL and I can't create a UDF. 我正在使用PostgreSQL,但无法创建UDF。 The table looks like this: 该表如下所示:

id  | user_id  | account_number
-------------------------------
 1  |    1     | 12345671
 2  |    4     | 12356673
 3  |    7     | 12325678

The id and user_id are integers whereas the account number is a string. id和user_id是整数,而帐号是字符串。 I'd like to select the account numbers that match the following conditions: 我想选择符合以下条件的帐号:

  • Account number string contains exactly 8 digits 帐号字符串包含正好8位数字
  • Validation scheme 验证方案
    1. Take the first 7 digits 取前7位数字
    2. Multiply the first digit by 1, the second by 2, the third by 3, the fourth by 1, the fifth by 2, the sixth by 3 and the seventh by 1 第一个数字乘以1,第二个数字乘以2,第三个数字乘以3,第四个数字乘以1,第五个乘以2,第六个乘以3,第七个乘以1
    3. Sum the result of multiplying each digit by the relevant number 将每个数字与相关数字相乘的结果相加
    4. If the 8th digit is the same as mod(sum, 10) then select this number 如果第8位与mod(sum,10)相同,则选择此数字

In this table above, I should only return the first two rows with the query. 在上表中,我应该只返回查询的前两行。

Just to repeat, I can't create a UDF, so am looking to find out whether this is possible using ordinary SQL in a query. 只是重复一遍,我无法创建UDF,因此希望找出在查询中使用普通SQL是否可行。

Thanks! 谢谢!

Yes, you can do it. 是的,您可以做到。 Basically, use SIMILAR TO to check for exactly 8 digits, then substring and cast to do the math. 基本上,使用SIMILAR TO来检查精确的8位数字,然后使用子字符串进行转换并进行数学运算。 Something like this: 像这样:

SELECT * FROM table_name WHERE
  account_number SIMILAR TO '[0-9]{8}'
  AND (
    1 * CAST(SUBSTR(account_number, 1, 1) AS INTEGER) +
    2 * CAST(SUBSTR(account_number, 2, 1) AS INTEGER) +
    3 * CAST(SUBSTR(account_number, 3, 1) AS INTEGER) +
    1 * CAST(SUBSTR(account_number, 4, 1) AS INTEGER) +
    2 * CAST(SUBSTR(account_number, 5, 1) AS INTEGER) +
    3 * CAST(SUBSTR(account_number, 6, 1) AS INTEGER) +
    1 * CAST(SUBSTR(account_number, 7, 1) AS INTEGER)
  )%10 = CAST(SUBSTR(account_number, 8, 1) AS INTEGER)

Of course, this returns no rows in your example, because: 当然,在您的示例中,此操作不返回任何行,因为:

1×1 + 2×2 + 3x3 + 1×4 + 2×5 + 3×6 + 1×7 = 53
53 MOD 10 = 3
3 ≠ 1

PS: You do realize the UDFs can be written in languages other than CEg, you can write one in PL/pgSQL. PS:您确实意识到UDF可以用CEg以外的语言编写,您可以用PL / pgSQL编写。

Just create a table where you split out your digits, then do the arithmetic (of course, you can fill in the rest of the stuff where the ... s are). 只需创建一个表,将数字分开即可,然后进行算术运算(当然,您可以在...所在的位置填充其余内容)。

create table digits as
select account_number,
substr(account_number::text,0,1)::int as digit_1
,substr(account_number::text,1,1)::int as digit_2
,...
substr(account_number::text,7,1) as digit_8
from table
where account_number::text~E'[0-9]{8}'; --regex to make sure acct numbers are of the right form.

select account_number,
(digit_1+2*digit_2+...+3*digit_6+dight_7)%10=digit_8 as valid
from digits;

Of course, if you'd rather not create a separate table, you can always put the select statement for the creation of the digits table into a subquery for the second query. 当然,如果您不想创建单独的表,则始终可以将用于创建digits表的select语句放入第二个查询的子查询中。

select id, 
       user_id,
       digit_sum, 
       last_digit 
from (
  select id, 
         user_id,
         (substring(account_number,1,1)::int + 
          substring(account_number,2,1)::int * 2 + 
          substring(account_number,3,1)::int * 3 + 
          substring(account_number,4,1)::int + 
          substring(account_number,5,1)::int * 2 + 
          substring(account_number,6,1)::int * 3 +
          substring(account_number,7,1)::int ) as digit_sum, 
          substring(account_number,8,1)::int as last_digit
  from accounts
) t
where last_digit = digit_sum % 10

To make life easier, I would create a view that does the splitting and summing of the values. 为了使生活更轻松,我将创建一个视图,对值进行拆分和求和。 Then you just need to select from that view with the where condition I used for the derived table. 然后,您只需要从该视图中选择我用于派生表的where条件即可。

You can try something along these lines. 您可以尝试以下方法。

select *,   (
    (substring(account_number from 1 for 1)::integer * 1) +
    (substring(account_number from 2 for 1)::integer * 2) +
    (substring(account_number from 3 for 1)::integer * 3) +
    (substring(account_number from 4 for 1)::integer * 1) +
    (substring(account_number from 5 for 1)::integer * 2) +
    (substring(account_number from 6 for 1)::integer * 3) +
    (substring(account_number from 7 for 1)::integer * 1)
   ) as sums,
  (
    (substring(account_number from 1 for 1)::integer * 1) +
    (substring(account_number from 2 for 1)::integer * 2) +
    (substring(account_number from 3 for 1)::integer * 3) +
    (substring(account_number from 4 for 1)::integer * 1) +
    (substring(account_number from 5 for 1)::integer * 2) +
    (substring(account_number from 6 for 1)::integer * 3) +
    (substring(account_number from 7 for 1)::integer * 1)
   ) % 10 as mod_10
from acct_no
where length(account_number) = 8 

I wrote the calculation into the SELECT clause instead of the WHERE clause, because either my arithmetic is wrong or your specs are wrong. 我将计算结果写到SELECT子句中而不是WHERE子句中,因为我的算法错误或您的规范错误。

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

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