首页 > 数据库 >sql server 动态查询空格问题

sql server 动态查询空格问题

时间:2024-05-21 17:09:37浏览次数:22  
标签:123456 no -- server 空格 item sql table 查询

一个奇怪的bug,之前遇到过,今天再次遇到了,这里说一下,先看如下SQL:

-- 存在这个表则删除
IF OBJECT_ID(N't_pl_table',N'U') is not NULL
BEGIN
DROP TABLE t_pl_table
END
-- 创建一个表用来测试
CREATE TABLE t_pl_table
(
    item_no char(20)
)
-- 随便插入一条数据
INSERT INTO t_pl_table(item_no) VALUES('123456')
-- 常规like查询
SELECT * FROM t_pl_table WHERE item_no LIKE '123456'
-- 使用EXEC动态查询
EXEC ('SELECT * FROM t_pl_table WHERE item_no LIKE ''123456''')
DECLARE @SearchSQL NVARCHAR(MAX)
SET @SearchSQL = 'SELECT * FROM t_pl_table WHERE item_no LIKE @item_no'
-- 参数化动态查询1
EXEC sp_executesql @SearchSQL,N'@item_no nvarchar(20)',@item_no='123456'
-- 参数化动态查询2
EXEC sp_executesql @SearchSQL,N'@item_no varchar(20)',@item_no='123456'

  参数化动态查询1里面返回的结果是空的,现在对比SQL可以很明显看到是动态参数的类型不对, 应该是varchar,而不是nvarchar,两者的区别自行百度。

  只是一般我觉得这两个类型差别不大,没想到在动态SQL查询这里有明细的结果区别。

  看表结果,item_no是char类型,这个类型和varchar以及nvarchar都不一样,char(20),当字符串只有6位时,其余位会补空格,所以查出来的123456实际是“123456              ”,而不是“123456”

  这也是为什么动态参数查询时指定参数类型为nvarchar无法得到正确结果的原因。

  既然是空格,首先表结构是不允许改的,char就是char,设计如此,随便改表可能会引发一系列问题,那么怎么做呢,可能你会想到下面这个方法:

SET @SearchSQL = 'SELECT * FROM t_pl_table WHERE rtrim(item_no) LIKE @item_no'

  用rtrim去掉空格再like不就好啦,好啦?

  从结果上看确实可以解决问题,但是从做法上看不可取,where后面的列加函数,会影响索引,查询的时候不走索引会影响性能,所以这么做不是最优解。

  最后的做法就是动态参数化查询时参数的类型要和列的类型匹配。

  PS:C#里面,参数化查询是通过new SqlParameter实现的,最终生成的SQL之所以用nvarchar的原因在于new SqlParameter的时候没有指定参数类型,不指定默认就是nvarchar,一般不会有问题,但遇到上述情况就不行了。

 

-- 错误的示例
new SqlParameter("@item_no", itemNo) 
-- 正确的示例
new SqlParameter("@item_no", itemNo) { SqlDbType = SqlDbType.VarChar, Size = 100 }

  以上。

 

标签:123456,no,--,server,空格,item,sql,table,查询
From: https://www.cnblogs.com/sunshine-wy/p/18203669

相关文章

  • Oracle和MySQL的区别
    刚进公司接触到了Oracle,记录一下他们的区别,面试的时候也有问到过,而且上来就是千万级别的数据调优,嘻嘻,我只是一个3年java。题外话,甚至有一些公司会问我java跟C、python的区别,以及具体区别的例子,然后我如果回答上来了,他们会告诉我,这边只做后端而且只用java,笑嘻了就本人最近的使用和......
  • Mybaits使用SQL拦截器实现字符串修剪
    概述一般情况下,保存到数据库中的字符串类型的数据,我们一般都不希望它前后带着空格,类似于"哈哈哈"。在业务中,如果每一个保存到数据库中的SQL都去对字符串参数进行trim的操作,这是很繁琐的,且容易漏掉。解决方案使用Mybatis的拦截器,拦截每一个SQL,针对SQL中的字符串参数进行tr......
  • mysql
    存储引擎mysql表有几种类型/存储引擎?INNODB,MYISAM,MEMORY,CSV INNODB设计存储结构=内存区域+磁盘区域 刷盘策略: 存储方式特点innodbVSmyisamINNODB特点:1.支持ACID的事务,支持四种隔离级别。2.支持行级锁及外检约束,支持写并发。3.不存储总行数。4.一个innod......
  • mysql中主键、外键、约束、索引
    主键用于唯一标识表中每一行数据,外键用于建立表与表之间关联关系,约束用于限制表中数据的规则,索引用于加速查询。1.主键是一种用于唯一标识表中每一行数据的标识符。在Mysql中,主键可以是一个或多个列的组合,但是必须满足以下条件:主键列的值必须唯一,不能重复。主键列的值不能为......
  • 在Docker中安装SQL Server的ODBC驱动并添加Python测试代码
    #使用官方的Ubuntu20.04镜像作为基础镜像FROMubuntu:20.04#设置环境变量以避免交互式安装提示ENVDEBIAN_FRONTEND=noninteractive#更新包列表并安装必要的软件包RUNapt-getupdate&&\  apt-getinstall-y\  wget\  curl\  gnupg2\ ......
  • 在Docker中安装MySQL的ODBC驱动并添加Python测试代码
    #使用官方的Ubuntu镜像作为基础镜像FROMubuntu:20.04#设置环境变量以避免交互式安装提示ENVDEBIAN_FRONTEND=noninteractive#更新包列表并安装必要的软件包RUNapt-getupdate&&\  apt-getinstall-y\  build-essential\  curl\  apt-trans......
  • 在Docker中安装PostgreSQL的ODBC驱动并添加Python测试代码
    #使用官方的Ubuntu镜像作为基础镜像FROMubuntu:20.04#设置环境变量以避免交互式安装提示ENVDEBIAN_FRONTEND=noninteractive#更新包列表并安装必要的软件包RUNapt-getupdate&&\  apt-getinstall-y\  build-essential\  unixodbc\  unixo......
  • 创建你的-Mysql-数据库-全-
    创建你的Mysql数据库(全)原文:zh.annas-archive.org/md5/853FEC9D976A75004408D5A9A661EDD8译者:飞龙协议:CCBY-NC-SA4.0前言1995年发布的MySQL已成为最受欢迎的开源数据库系统。MySQL和phpMyAdmin的普及使得许多非IT专家能够使用MySQL后端构建动态网站。本书是一......
  • 二进制安装mysql5.7
    1.创建目录mkdir-p/server/toolsmkdir/applicationmkdir/mysql-data/mysql/data-p2.建用户与环境变量useradd-s/sbin/nologinmysqlecho"exportPATH=/application/mysql/bin:$PATH">>/etc/profilesource/etc/profile3.下载与解压文件cd/server/tools/wg......
  • SQL Server 触发器利用临时表在外检表插入前插入主键表
    在SQLServer中,你可以使用触发器(trigger)来在插入学生信息之前,根据班级名称在班级表中插入相应的班级记录。这通常涉及到两步:首先,检查班级表中是否已存在相应的班级;如果不存在,则插入;然后,允许插入学生记录。下面是一个示例,展示如何创建这样的触发器:假设你有两个表:Students 和 C......