sql - 根据列的数据类型动态构建 SQL 查询
问题描述
在我的应用程序中,我有一个功能,用户可以输入多个搜索字段,这些字段将用于查询数据库,例如,用户输入:
史密斯 123456 伦敦 12/01/2020
这些字段将作为表值参数(由一列作为 varchar 组成)传递给存储过程。sp 使用视图作为其数据源。例如对于上面的自定义搜索,会有一个包含以下列的视图:
number, int
firstname, varchar
lastname, varchar
dob, datetime
address, varchar
sp需要动态构建sql查询,这个查询应该是这样的
select * from customersview
where 'smith' in (firstname, lastname, address)
and 123456 in (number)
and 'london' in (firstname, lastname, address)
and '12/01/2029' in (dob)
所以基本上, sp 所做的是:
- 使用搜索过滤器并确定它们是什么数据类型
- 将过滤器的数据类型映射到列的数据类型,例如,将
int
过滤器映射到所有int
列等。
所以我从以下开始:
select COLUMN_NAME, DATA_TYPE
from INFORMATION_SCHEMA.VIEWS v
join INFORMATION_SCHEMA.COLUMNS c on c.TABLE_SCHEMA = v.TABLE_SCHEMA
and c.TABLE_NAME = v.TABLE_NAME
where c.TABLE_NAME = 'customersview'
这将为我提供视图的列及其数据类型。
但是我如何匹配数据类型(因为过滤器来自 TVP),以便我可以构建各种条件?
或者,我可以更改 TableType,使其具有 3 个唯一列(int、varchar、datetime),并且应用程序确定数据类型并将值添加到正确的列中。
解决方案
我只是尝试使用 while 循环构建查询并检查数据类型,如下所示。
为了便于理解,我在查询本身中添加了注释。
待办事项:
1-您需要在以下查询中添加其他数据类型。
2-您需要参数化查询并使用sp_executesql
而不是执行以避免任何sql注入攻击。
--Table to Store search inputs, which will be your table type parameter.
DECLARE @v TABLE (searchString VARCHAR(100))
--Sample Inputs
INSERT INTO @v
SELECT *
FROM (
VALUES ('smith')
,('1234')
,('london')
,('12/01/2020')
) t(v)
IF OBJECT_ID('tempdb..#Temp') IS NOT NULL
DROP TABLE #Temp
--Create a temporary table to loop the serach inputs
SELECT *
,0 AS IsProcessed
INTO #Temp
FROM @v
DECLARE @query NVARCHAR(max) = 'SELECT * FROM customersview WHERE 1 = 1 '
DECLARE @searchString VARCHAR(100)
--Loop through each search input
WHILE (
SELECT Count(*)
FROM #Temp
) > 0
BEGIN
SELECT TOP 1 @searchString = searchString
FROM #Temp
SELECT @searchString
--Check if input is int/bigint type
IF (ISNUMERIC(@searchString) = 1)
BEGIN
SET @query = @query + 'AND ' + @searchString + ' IN (' + Stuff((
SELECT DISTINCT ', ' + Quotename(COLUMN_NAME)
FROM (
SELECT COLUMN_NAME
,DATA_TYPE
FROM INFORMATION_SCHEMA.VIEWS v
JOIN INFORMATION_SCHEMA.COLUMNS c ON c.TABLE_SCHEMA = v.TABLE_SCHEMA
AND c.TABLE_NAME = v.TABLE_NAME
WHERE c.TABLE_NAME = 'customersview'
AND DATA_TYPE IN ('int', 'bigint')
) t
FOR XML path('')
,type
).value('.', 'NVARCHAR(MAX)'), 1, 1, '') + ')'
END
--Check if input is date type
ELSE IF (ISDATE(@searchString) = 1)
BEGIN
SET @query = @query + ' AND ''' + @searchString + ''' IN (' + Stuff((
SELECT DISTINCT ', ' + Quotename(COLUMN_NAME)
FROM (
SELECT COLUMN_NAME
,DATA_TYPE
FROM INFORMATION_SCHEMA.VIEWS v
JOIN INFORMATION_SCHEMA.COLUMNS c ON c.TABLE_SCHEMA = v.TABLE_SCHEMA
AND c.TABLE_NAME = v.TABLE_NAME
WHERE c.TABLE_NAME = 'customersview'
AND DATA_TYPE IN ('date', 'datetime')
) t
FOR XML path('')
,type
).value('.', 'NVARCHAR(MAX)'), 1, 1, '') + ')'
END
ELSE
BEGIN
--Check if input is VARCHAR/NVARCHAR type
SET @query = @query + ' AND ''' + @searchString + ''' IN (' + Stuff((
SELECT DISTINCT ', ' + Quotename(COLUMN_NAME)
FROM (
SELECT COLUMN_NAME
,DATA_TYPE
FROM INFORMATION_SCHEMA.VIEWS v
JOIN INFORMATION_SCHEMA.COLUMNS c ON c.TABLE_SCHEMA = v.TABLE_SCHEMA
AND c.TABLE_NAME = v.TABLE_NAME
WHERE c.TABLE_NAME = 'customersview'
AND DATA_TYPE IN ('VARCHAR', 'NVARCHAR')
) t
FOR XML path('')
,type
).value('.', 'NVARCHAR(MAX)'), 1, 1, '') + ')'
END
DELETE #Temp
WHERE searchString = @searchString
END
SELECT @query
--Execute the query
--EXEC(@Query)
推荐阅读
- unix - 几秒钟后,Logstash 服务单独停止
- angular - 如何修复“错误:StaticInjectorError(AppModule)[NgbDropdown -> ChangeDetectorRef]”
- google-sheets - OAuth 客户端已删除
- angular - 理解复杂的类型脚本类型声明
- lambda - 使用 Cognito 在 lambda 中部署时,如何在没有 cookie 和会话的情况下保持 Django REST API 无状态
- c++ - 预处理器定义在发布模式下工作,而不是在调试模式下工作
- python - 我可以在 buildroot 中安装 wheel 包吗?
- bash - bash 仅针对用户输入的第一个字符读取超时
- python - 用python的正则表达式匹配多组字符
- android - Dagger2 作用域片段的问题