以文本方式查看主题

-  Foxtable(狐表)  (http://foxtable.net/bbs/index.asp)
--  专家坐堂  (http://foxtable.net/bbs/list.asp?boardid=2)
----  多表联合查询where条件的问题  (http://foxtable.net/bbs/dispbbs.asp?boardid=2&id=121030)

--  作者:happyft
--  发布时间:2018/6/27 18:53:00
--  多表联合查询where条件的问题
项目的进出仓单据有二十种左右,现在为了查询某个产品的出入库明细信息,将二十个表用union all连接起来再通过统一的where条件查询,
现在数据量有近百万,有时速度非常慢,想把where条件先传入到每个表的查询中最后再union all在一起,这样是否快些?
但问题来了,原来设计时没考虑这点,所以各个表中的字段取名不一致,比如日期有入库日期,出库日期,报废日期等,现在如果要传入给每个表的查询where条件用却无法实现了,查询窗口中只有一个日期字段,这个传入的日期参数无法通用于每张单,除了将每个基表的日期字段改为相同名字外,还有没有其他办法?

谢谢!


--  作者:有点甜
--  发布时间:2018/6/27 20:31:00
--  

union all 会生成一个临时表,把所需的数据填充到这个表格的,数据量越大,肯定就越慢。

 

你现在这种情况,就动态合成sql语句呗。定义好每个表对应的日期字段分别是什么,然后分别合成select语句加上where条件,最后union。


--  作者:HappyFt
--  发布时间:2018/6/28 11:28:00
--  

ft中,每个表动态合成sql语句后可以用AppendLine()每条加在一起最后统一执行,如果直接在sql的储存过程中是不是每个表拼接好sql语句后像下面这样:

Declare @Sql nvarchar(max),@Sql2 nvarchar(max)

IF @tbn = \'1\'

  Begin

    Se t @Sql2=\'.....\'

    Se t @Sql=@Sql+@sql2

  End

elseif  @tbn = \'2\'

  Begin

    Se t @Sql2=\'.....\'

    Se t @Sql=@Sql+@sql2

 end

最后Exec (@Sql)




--  作者:有点甜
--  发布时间:2018/6/28 11:31:00
--  

是要分别判断在where那里合成不同条件的,把所有sql语句最后union在一起运行即可。


--  作者:HappyFt
--  发布时间:2018/6/28 11:50:00
--  
分别合成where条件这个明白, 我是想问如何将每一个包括不同where条件的sql语句union 在一起
Se t @Sql2=\'..... + \'union all\' + char(10)

Se t @Sql=@Sql+@sql2


这样的方式不可以吗?


--  作者:有点甜
--  发布时间:2018/6/28 13:32:00
--  
你现在这样做有什么问题?字符串无法合并起来?
--  作者:HappyFt
--  发布时间:2018/6/28 17:44:00
--  
做是做出来了,为什么先where查询后再union所有表的速度与全部表union后后再where的速度差不多呢?
--  作者:有点甜
--  发布时间:2018/6/28 18:06:00
--  
以下是引用HappyFt在2018/6/28 17:44:00的发言:
做是做出来了,为什么先where查询后再union所有表的速度与全部表union后后再where的速度差不多呢?

 

数据量相差多少?假如全部表数据有100万行,加入where条件后是100行数据,运行看速度变化。


--  作者:HappyFt
--  发布时间:2018/6/28 18:44:00
--  
直接在sql里面执行查询的数据,都是远程数据库
SE LECT [_Identify],
    [sys_Fzt],
    [sys_Over],
    [进出单号],
    [进出日期],
    [进出单位],
    [仓库],
    [仓管员],
    [产品编码],
    [来源单号],
    [品名],
    [规格],
    [工序号],
    [入库数量],
    [出库数量],
    [进出数量],
    [计量单位],
    [品质判定],
    [进出类别],
    [盘点序号],
    [品质状态]
FROM [dbo].[uv_ck110]  --uv_ck110这个视图就是没有where条件将每个表数据直接union的
WHERE 进出日期 > \'2018-06-26\'
上面是直接在后面加条件的查询 ,

而先用了where条件再union的是通过调用储存过程来测试的如下:
EXEC @return_value = [dbo].[usp_kcinout] @whereflt = N\'进出日期 > \'\'2017-06-26\'\'\'

用了2018-06-26,2017-06-26,2014-06-26三个日期分别执行查询出来的数据时间都是差不多的
1199条/1秒内,20万/29秒,70万/1分48秒

是不是我的动态sql语句拼接的不正确啊,但又没发现哪里有错,sql语句如下(共有23个表中查询)
@whereflt是传入条件
  DECLARE @sql NVARCHAR(MAX);
    DECLARE @sql2 NVARCHAR(MAX);
    DECLARE @flt NVARCHAR(400);
    SE T @flt = REPLACE(@whereflt, \'进出日期\', \'入库日期\');  --替换进出日期
    SE T @sql2
        = \'
      SE LECT  a._Identify ,
            a.sys_Fzt ,
            b.sys_Over ,
            b.入库单号 AS 进出单号 ,
            a.入库日期 AS 进出日期 ,
            a.入库单位 AS 进出单位 ,
            a.仓库 ,
            a.仓管员 ,
            b.产品编码 ,
            b.来源单号 ,
            b.品名 ,
            b.规格 ,
            0 AS 工序号 ,
            b.数量 AS 入库数量 ,
            0 AS 出库数量 ,
            b.数量 AS 进出数量 ,
            b.计量单位 ,
            品质判定 ,
            \'\'采购入库\'\' AS 进出类别 ,
            0 AS 盘点序号 ,
            CASE WHEN b.品质判定 IN ( \'\'合格\'\', \'\'特采\'\' ) THEN \'\'合格品\'\'
                 WHEN b.品质判定 IN ( \'\'选别\'\', \'\'退货\'\' ) THEN \'\'不良品\'\'
                 WHEN b.品质判定 = \'\'报废\'\' THEN \'\'报废品\'\'
                 ELSE \'\'待检品\'\'
            END AS 品质状态
    FROM 采购入库单 a
            INNER JOIN 采购入库明细 b ON a.入库单号 = b.入库单号
            where \' + @flt;
    SE T @sql = @sql2 + \'Union all \' + CHAR(10);

    SE T @flt = REPLACE(@whereflt, \'进出日期\', \'退货日期\'); --替换进出日期
    SE T @sql2
        = \'       
    SE LECT  a._Identify ,
            a.sys_Fzt ,
            b.sys_Over ,
            b.退货单号 AS 进出单号 ,
            a.退货日期 AS 进出日期 ,
            a.收货单位 AS 进出单位 ,
            a.仓库 ,
            a.仓管员 ,
            b.产品编码 ,
            b.来源单号 ,
            b.品名 ,
            b.规格 ,
            0 AS 工序号 ,
            -b.数量 AS 入库数量 ,
            0 AS 出库数量 ,
            -b.数量 AS 进出数量 ,
            b.计量单位 ,
            品质状态 ,
            \'\'采购退货\'\' AS 进出类别 ,
            0 AS 盘点序号 ,
         CASE WHEN b.品质状态 = \'\'合格品\'\' THEN \'\'合格品\'\'
                 WHEN b.品质状态 = \'\'不良品\'\' THEN \'\'不良品\'\'
                 WHEN b.品质状态 = \'\'报废品\'\' THEN \'\'报废品\'\'
                 ELSE \'\'待检品\'\'
            END AS 品质状态
    FROM    dbo.采购退货单 AS a
            INNER JOIN 采购退货明细 AS b ON a.退货单号 = b.退货单号
            where \' + @flt;
    SE T @sql = @sql + @sql2 + \'Union all \' + CHAR(10);
其他表相同,最后再
 EXEC sp_executesql @sql



--  作者:有点甜
--  发布时间:2018/6/28 21:56:00
--  

如果执行 1199条/1秒内 的话,说明没有区别。

 

耗时不在where条件,而在拷贝数据到临时表那个操作。因为20万条的时候耗时较多。

 

一般在foxtable显示的时候,不需要全部显示过来吧?如果只是显示少量,加上top取少量数据试试。