【问题标题】:MySQL: CONCAT/SUBSTRING: Does this not work because I am using an int variable?MySQL:CONCAT/SUBSTRING:这不起作用,因为我使用的是 int 变量吗?
【发布时间】:2016-07-17 16:51:44
【问题描述】:

我正在尝试以四个为一组编写一个信用卡号,最多为十六位。我正在使用 CONCAT 和 SUBSTRING 来执行此操作。

注意:我没有收到错误,它运行但输出不是我想要的。

我想要的是这个:xxxx-xxxx-xxxx-xxxx 我得到了什么:2147-4836-47-(不仅在一个位置,而且在所有四个条目中)

这是因为我试图在下标语句中分解一个 int 变量吗?您可以在 substring() 中使用 int 字符吗? BIGINT 呢?

不管我为什么将其更改为 varchar,并使用 CONCAT 和 SUBSCRIPT 运行它。一切似乎都很好,但欢迎进一步输入。 :)

创建的表:

CREATE TABLE credit_cards
(
credit_card_ID          int(10)             UNIQUE,
credit_card_num         int(20)         NOT NULL,
exp_date                DATE                NOT NULL,
card_fname              varchar(35)         NOT NULL,
card_lname              varchar(35)         NOT NULL,
security_code           int(5)              NOT NULL,
bill_street             varchar(50)         NOT NULL,
bill_city               varchar(25)         NOT NULL,
bill_state              varchar(2),
bill_zip                int(10)             NOT NULL,
PRIMARY KEY (credit_card_ID)
);

插入数据:

INSERT INTO credit_cards VALUES 
(1, 0025184796520000, '2016-08-13', 'Sarah', 'Jones', 3351, '2490 Paseo Verde parkway, suite 150', 'San Diego','CA',92124),
(2, 7896541232548526, '2017-09-21', 'Desmond', 'Lowell', 1204, '3201 Kelsey Street, suite 109', 'San Diego','CA',92174),
(3, 1234567890123456, '2018-02-11', 'Mark', 'Jefferson', 1591, '876 Silverado Street, suite 304', 'Henderson','NV',89162),
(4, 4001330852539605, '2017-01-10', 'Jaime', 'Evans', 8879, '924 Shady Pines Circle, suite 120', 'Summerlin','NV',89074);

选择数据

SELECT credit_card_ID as 'Card ID', 
        CONCAT(
        SUBSTRING(credit_card_num, 1,4), '-',
        SUBSTRING(credit_card_num, 5,4), '-',
        SUBSTRING(credit_card_num, 9,4), '-',
        SUBSTRING(credit_card_num, 13,4)) as 'Card Number',
        security_code as 'Security Code',
        DATE_FORMAT(exp_date, '%m-%d-%Y') as 'Expiration Date', 
        CONCAT(card_fname, ' ', card_lname) as 'Customer Name',
        CONCAT(bill_street, ', ', bill_city, ', ', bill_state, ' ', bill_zip) as 'Billing Address'
FROM credit_cards
ORDER BY exp_date ASC;

【问题讨论】:

  • 如果您关心前导零,那么您就没有数字。您应该使用字符串。您可以使用lpad() 附加它们,这应该可以修复您的代码。
  • 感谢您的建议。 :) 我从未听说过 lpad(),但我会彻底研究它。我只是将其更改为 VARCHAR,并发现了其他一些我认为让它变得不稳定的东西。它现在与 CONCAT 和 SUBSCRIPT 一起工作得很好,但我对 lpad 很好奇。我一定会检查出来的。
  • 另外你必须使用BIGINTINT 不会占用 20 位数字。见:MySql Docs
  • 哦!这真是太好了!非常感谢! :)
  • 注意:LPAD 函数是一个字符串函数。它对字符串进行操作。与整数参数一起使用时,参数会自动转换为 VARCHAR,然后 LPAD 对返回的字符串进行操作。也就是说,有一个从整数到 varchar 的隐式转换/转换。

标签: mysql sql int substring concat


【解决方案1】:

有两个问题:

1) INT 不能为 16 位,必须使用 BIGINT

Integer types documentation for MySQL 5.7

CREATE TABLE `credit_cards` (
    `credit_card_ID` INT(10) NOT NULL,
    `credit_card_num` BIGINT(16) NOT NULL,       -- use BIGINT here
    `exp_date` DATE NOT NULL,
    `card_fname` VARCHAR(35) NOT NULL,
    `card_lname` VARCHAR(35) NOT NULL,
    `security_code` INT(5) NOT NULL,
    `bill_street` VARCHAR(50) NOT NULL,
    `bill_city` VARCHAR(25) NOT NULL,
    `bill_state` VARCHAR(2) NULL DEFAULT NULL,
    `bill_zip` INT(10) NOT NULL,
    PRIMARY KEY (`credit_card_ID`),
    UNIQUE INDEX `credit_card_ID` (`credit_card_ID`)
);

2) 前导零通常被切断。您必须使用 LPAD。

LPAD documentation for MySQL 5.7

LPAD(credit_card_num, 16, 0)

读取:左填充 credit_card_num 与 0 到 16 位的长度。查询可能如下所示:

SELECT credit_card_ID as 'Card ID', 
        CONCAT(
        SUBSTRING(LPAD(credit_card_num, 16, 0), 1,4), '-',
        SUBSTRING(LPAD(credit_card_num, 16, 0), 5,4), '-',
        SUBSTRING(LPAD(credit_card_num, 16, 0), 9,4), '-',
        SUBSTRING(LPAD(credit_card_num, 16, 0), 13,4)) as 'Card Number',
        security_code as 'Security Code',
        DATE_FORMAT(exp_date, '%m-%d-%Y') as 'Expiration Date', 
        CONCAT(card_fname, ' ', card_lname) as 'Customer Name',
        CONCAT(bill_street, ', ', bill_city, ', ', bill_state, ' ', bill_zip) as 'Billing Address'
FROM credit_cards
ORDER BY exp_date ASC;

See it live.

【讨论】:

  • 非常感谢您预览 LPAD。这实际上很有趣,我很高兴能玩弄它! :)
【解决方案2】:

不管它值多少钱,我根本不会使用整数来存储信用卡号。我会使用 CHAR(16)--not VARCHAR 因为字符串的大小永远不会改变。我会解释原因。

除非您打算在某种形式的计算中使用数字,否则没有理由使用任何类型的整数变量。将它们存储为字符串(即 CHAR、VARCHAR、NCHAR 或 NVARCHAR)更容易,因为您要从一些必须跳过的圈子中找出您想要的东西。即使您要进行某种形式的校验位验证,与从整数中获取数字值的子集相比,从字符串中剥离数字并将结果转换为整数的麻烦也会更少。

事实上,当您将 SUBSTRING 应用于整数时,解析器会在应用之前将整数隐式转换为字符串,因此在这种情况下使用某种形式的整数类型时会产生额外的开销。你会很好地问自己是否需要额外的开销,如果需要,为什么。如果不需要,您应该考虑将简化作为一般原则。

请务必牢记,数字通常最好可视化为字母数字字符集的子集,您可能会问自己为什么需要将信用卡号视为具有数学能力的数字(即整数)而不是纯字符数据。这里很容易出错,因为它有点违反直觉:标准的初学者错误是将邮政编码存储为整数,然后想知道如何让东海岸号码中的前导零计算出来。任何尝试将邮政编码放入 Excel 电子表格的人都遇到过这个。

【讨论】:

  • 我同意不将整数数据类型用于信用卡号或社会保险号。关于这些值未在执行算术的表达式中使用的观点是有效的。但是人们可能会考虑使用数字类型的一个可能原因是,这样做会强制限制哪些“字符”可以存储在列中。我并不是说这种考虑凌驾于其他顾虑之上。我只是建议可能已经考虑了一种方法来强制执行有关允许哪些字符的规则。本机“信用卡号”数据类型不可用。
  • @spencer7593 。 . .并非所有数字都是有效的信用卡号(请参阅 Luhn 算法),因此仅检查数字是不够的。
  • @GordonLinoff:你完全正确。我并没有暗示整数数据类型足以验证信用卡号。我正在解决 Bob 的断言 “没有理由使用任何类型的整数变量,除非您打算在某种形式的计算中使用这些数字。” 我不相信 Bob 的断言严格来说是正确的,因为我相信在某些情况下整数类型可以适用于不会在计算中使用的值。 (我之前的评论同意整数不是存储信用卡号码的合适数据类型。)
  • @spencer7593 一种更便宜的方法是在字段定义中添加一个 CHECK 约束。例如:CHECK ( [credit_card_num] LIKE '[3-6][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]' ) 将限制条目仅限于主要信用卡(它们以 3 到 6 开头),而允许第一位数字为 7 将包括加油站卡。此外,我的断言可能更好地描述为“普遍正确”。 :) 最后,正如 Gordon 指出的那样,您还必须为 Luhn 算法添加一个约束。
  • 不幸的是,MySQL 不强制执行 CHECK 约束或用户定义类型。因此,当我们将对象映射到关系模型时,就会出现“阻抗不匹配”。 ORM 框架做得足够好,并围绕“将所有内容存储为字符串”进行导航。一些关系数据库(除了 MySQL)确实为用户定义的类型(或 Date 等人所指的“域”)提供了更好的支持。所以我们仍然存在将更复杂的类型(例如“信用卡号”)映射到数据库支持的实际数据类型的问题。
猜你喜欢
  • 2022-01-26
  • 1970-01-01
  • 2019-07-27
  • 1970-01-01
  • 1970-01-01
  • 2019-09-17
  • 1970-01-01
  • 2014-03-29
  • 2020-06-16
相关资源
最近更新 更多