[英]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: 我想选择符合以下条件的帐号:
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.