logo SQL Prompt教程 我也要发布文档

SQL语法提示工具SQL Prompt教程:使用没有明确长度的可变长度数据类型(下)


SQL Prompt根据数据库的对象名称、语法和代码片段自动进行检索,为用户提供合适的代码选择。自动脚本设置使代码简单易读--当开发者不大熟悉脚本时尤其有用。SQL Prompt安装即可使用,能大幅提高编码效率。此外,用户还可根据需要进行自定义,使之以预想的方式工作。

点击下载SQL Prompt免费版

如果您声明一个可变长度的字符串,或在不指定其长度的情况下强制字符串,则可能会被“静默”字符串截断。一些开发人员诉诸使用(MAX)规范,这也是一个错误。当您导入文本并且根本不知道每个字符串的正确长度时,Phil Factor解释了其中的危险,然后提供了解决该问题的方法。本文是该教程的后半部分内容,紧接前文内容~

在数据导入期间使用表值构造函数分配合理的字符串长度

SQL Server可以做得更好,而不是像这样耸耸肩就放弃。当它需要时,它可能会非常聪明。例如,它可以在像这样的表值构造函数( TVC )语句中计算出数据类型的长度及其可空性。

SELECT name
    FROM (VALUES --one to twenty 
  ('Yan'), --in Lincolnshire dialect
  ('Tyan'),
  ('Tethera'),
  ('Methera'),
  ('Pimp'),
  ('Sethera'),
  ('Lethera'),
  ('Hovera'),
  ('Dovera'),
  ('Dik'),
  ('Yanadik'),
  ('Tyanadik'),
  ('Tetheradik'),
  ('Metheradik'),
  ('Bumfitt'),
  ('Yanabumfit'),
  ('Tyanabumfitt'),
  ('Tetherabumfitt'),
  ('Metherabumfitt'),
  ('Giggot'))f(name)

如果使用此TVC SELECT INTO表,您将能够看到它创建了一个VARCHAR列,该列的长度为该列中值的最长字符串(在此cas中,“Tetherabumfitt”和“Metherabumfitt”;14个字符)。

我们可以通过带有临时表的SELECT INTO轻松地验证这一点……

SELECT name INTO #MyTemp
    FROM (VALUES --one to twenty 
  ('Yan'), --in Lincolnshire dialect
  ('Tyan'),
   ...etc ...
  ('Giggot'))f(name)

…然后检查创建的列的宽度…

SELECT system_type_name FROM 
   sys.dm_exec_describe_first_result_set('SELECT * FROM #MyTemp',NULL,1)
   /*system_type_name
     varchar(14)
   */

这表明如果您需要从外部的基于文本的源(其中包含一个包含很多字符串的繁琐的表)进行导入,那么确保获得合理长度的字符串数据类型的最佳方法是使用TVC。

在INSERT INTO…VALUES语句中使用时,TVC的行数限制为1000行,如果超出该行,则会看到错误10738。 但是,就像上面说明的那样,在使用VALUES的SELECT INTO语句中使用TVC时,我无法检测到任何限制。

让我们尝试一下。这是业务目录的首次导入,当然是用SQL Data Generator欺骗的。如果您想一起玩,可以从我的表没有聚集索引(BP021)的文章中下载构建脚本和.sqlgen文件。为了证明这一点,我们将前1000行放入SSMS的网格视图中。

SELECT TOP 1000 * FROM bigdirectory

SQL语法提示工具SQL Prompt教程:使用没有明确长度的可变长度数据类型(下)

现在,如果您有SQL Prompt,则在阅读本文时会在椅子上来回摆动,因为您在这里有相当不错的优势。单击网格的左上角正方形以突出显示整个批次,然后单击鼠标右键并选择“脚本作为插入”选项。

SQL语法提示工具SQL Prompt教程:使用没有明确长度的可变长度数据类型(下)

SQL Prompt在INSERT INTO

在这种情况下,我们将坚持使用1000行,并略微修改此代码以使其SELECT INTO与TVC中的临时表配合使用,从而避免使用1000行的限制:

SQL语法提示工具SQL Prompt教程:使用没有明确长度的可变长度数据类型(下)

……依此类推,直到……

SQL语法提示工具SQL Prompt教程:使用没有明确长度的可变长度数据类型(下)

执行上面的代码,让我们再次使用方便的sys.dm_exec_describe_first_result_set DMV,以获取SELECT * FROM #temptable查询结果集的元数据:

SELECT name + ' ' + system_type_name
         + CASE WHEN is_nullable = 1 THEN ' NULL' ELSE ' NOT NULL' END
    FROM sys.dm_exec_describe_first_result_set('
  SELECT * FROM #temptable', NULL, 1);

它为每列指定了数据类型、长度和可空性,如下所示(要使其正常工作,示例行中将需要一些长字符串和空值):

id int NOT NULL
Name varchar(37) NOT NULL
Address1 varchar(34) NULL
Address2 varchar(23) NULL
Town varchar(22) NOT NULL
City varchar(19) NOT NULL
County varchar(18) NOT NULL
Postcode varchar(8) NOT NULL
Region varchar(22) NOT NULL
BusinessType varchar(55) NULL
Leads varchar(17) NULL
Phone varchar(12) NULL
Fax varchar(12) NULL
Website varchar(56) NULL

我已经对此进行了多达10000行的测试,但其他方面做得更多。一旦所有列都有正确的数据类型、长度和可空性,就可以对长度进行一些舍入,以允许出现异常值,创建一个良好的整洁表,然后使用它导入整个数据(在这个实验中为400万行)。

CREATE TABLE BusinessDirectory
    (
    id INT NOT NULL,
    Name VARCHAR(40) NOT NULL,
    Address1 VARCHAR(40) NULL,
    Address2 VARCHAR(50) NULL,
    Town VARCHAR(30) NOT NULL,
    City VARCHAR(20) NOT NULL,
    County VARCHAR(20) NOT NULL,
    Postcode VARCHAR(8) NOT NULL,
    Region VARCHAR(30) NOT NULL,
    BusinessType VARCHAR(60) NULL,
    Leads VARCHAR(20) NULL,
    Phone VARCHAR(15) NULL,
    Fax VARCHAR(15) NULL,
    Website VARCHAR(60) NULL
    );
  INSERT INTO BusinessDirectory
    (id, Name, Address1, Address2, Town, City, County, Postcode, Region,
  BusinessType, Leads, Phone, Fax, Website)
    SELECT id, Name, Address1, Address2, Town, City, County, 
  Postcode, Region, BusinessType, Leads, Phone, Fax, Website
      FROM BigDirectory;

如果您不喜欢这种方法,那么在这种情况下,您当然可以轻松地从原始表中获取最大实际长度。

但是,检测列是否可为空是比较棘手的。

SELECT Max(Len(Name)), Max(Len(Address1)), Max(Len(Address2)), Max(Len(Town)),
    Max(Len(City)), Max(Len(County)), Max(Len(Postcode)), Max(Len(Region)),
    Max(Len(BusinessType)), Max(Len(Leads)), Max(Len(Phone)), Max(Len(Fax)),
    Max(Len(Website))
    FROM BigDirectory;

从外部基于文本的源中导入时,TVC技术可能会很方便。但是,主要目的是向您展示SQL Server可以很好地检测字符串数据类型的正确长度和可空性。

结论

SQL Server要求您指定字符串数据类型的长度。您可能会认为,因为在保留长度时它并不反对,所以它会为您自动检测长度。不,一点都不。如果声明的列作为CHAR、NCHAR、VARCHAR或者NVARCHAR没有长度,SQL Server读取的长度将为1。这是任何可变长度的字符串来说,这都是一个愚蠢的长度,它等于毫无用处的废话,但我们仍然坚持使用它。

如果您定义的变量字符串没有长度,它将对您造成更可怕的后果。 它不仅会假定它的长度为1个字符,而且还会默默地谨慎地将分配给它的每个值减小为一个字符。 如果您未指定长度,则SQL Server决定将varchar减少为一个字符时,一定会感到很傻,因为如果在将数据类型转换为NVARCHAR或VARCHAR时犯同样的错误,它将产生一个带有更合理的长度为30。

始终为任何基于文本的数据类型指定长度,例如NVARCHAR或VARCHAR。也不要过度使用该MAX规范,因为结果列将无法被索引,并且会带来性能负担。

本教程内容到这里就完结啦,感兴趣的朋友可以继续关注我们,我们会不断更新相关资讯!您也可以下载SQL Prompt试用版进行测评~

相关内容推荐:

SQL语法提示工具SQL Prompt教程:使用没有明确长度的可变长度数据类型(上)


想要购买SQL Prompt正版授权,或了解更多产品信息请点击“咨询在线客服”

850×682.png