1

我正在尝试将一些代码从 FoxPro 转换为 SQL Server,但我遇到了非常奇怪的行为。

在 FoxPro 的应用程序中编写的这段代码:

lcZnak1 = "HM,P6";

SELECT Zakslozkap.datum,ABS(Zakslozkap.hodnota) hodnota, ABS(Zakslozkap.koruny)
koruny, Zakslozka.sekce;
FROM Zakslozkap, Zakslozka; 
WHERE (Zakslozkap.SW $ lcZnak1) AND;
BETWEEN(Zakslozkap.datum,Thisform.cDatOd,Thisform.cDatDo) AND ;
Zakslozkap.ide_slozka = Zakslozka.ide_slozka AND ;
Zakslozka.ide_zak = "6065" ;
INTO CURSOR QueryNakladMZD

SUM (koruny) FOR  sekce $ ('REZIE4') TO lnostat
SUM (koruny) FOR  sekce $ ('REZIE3') TO lnRezie
SUM (koruny) FOR  sekce $ ('SEKTOR') TO lnSekce
SUM (koruny) TO lnPodil

lnPodil= lnPodil - lnostat - lnRezie - lnSekce

产生 lnPodil = 1 721 761,07 的结果。

我用 SQL 编写的代码:

declare @lnOstat decimal(18,5) = 0
declare @lnRezie decimal(18,5) = 0
declare @lnSekce decimal(18,5) = 0
declare @lnPodil decimal(18,5) = 0  

select p.datum, abs(p.hodnota) as 'hodnota', abs(p.koruny) as 'koruny', z.sekce into #tmp
from [DOCHAZKA]...[zakslozkap] p, [DOCHAZKA]...[zakslozka] z
where (p.SW = 'HM' or p.SW = 'P6')
      and p.datum between @datestart and @dateend
      and p.ide_slozka = z.ide_slozka
      and z.ide_zak = '6065'

select @lnOstat = SUM(koruny) from #tmp where sekce = 'REZIE4'
select @lnRezie = SUM(koruny) from #tmp where sekce = 'REZIE3'
select @lnSekce = SUM(koruny) from #tmp where sekce = 'SEKTOR'
select @lnPodil = SUM(koruny) from #tmp

select @lnPodil = isnull(@lnPodil,0) - isnull(@lnOstat,0) - isnull(@lnRezie,0) - isnull(@lnSekce,0) 
drop table #tmp

产生@lnPodil = 1 623 779.67 的结果。

所以,有 100k 的差异,因为这是关于钱的,所以很多。我急于寻找解决方案,所以我在那里问。我的 SQL 翻译是否完全反映了 FoxPro 的代码?

表是一样的,所以数据。在 SQL 中,我使用链接服务器来访问这些 dbfs。字段“koruny”作为浮点数据类型存储在 dbf 中。

4

2 回答 2

2

如果有人将数据从 VFP 转换为 SQL Server,我想知道 VFP 中是否有标记为删除但未上传到 SQL Server 的记录。这在 VFP 中通过使用“SET DELETED ON”隐藏标记为删除的记录来处理。“SET DELETED OFF”允许看到已删除的记录(并最终包含在您的查询中)。

也就是说,然后我将通过检查 SQL 中的 @@rowcount 来确认查询中正在处理的记录的 COUNT 以查看它是否也匹配。

现在,有些事情不是“完全”VFP 是如何做事的,但基于概率,我认为你在其他方面没问题,那就是关于 VFP 中的“$”。“$”用来表示左边的东西在右边的字符串中的任何地方......

lcZnak1 = "HM,P6";

WHERE (Zakslozkap.SW $ lcZnak1)

你的转换为

其中 p.SW = 'HM' 或 p.SW = 'P6'

可能没问题,但这就是区别

假设您在“M”或“P”,甚至“M”或“P”,甚至“HM,P”,“HM”,“”的“SW”列中有一个值, P6”等他们都符合资格。它几乎就像 SQL 中的 LIKE 命令。同样在底部的总结中。但是,如果您的列的“x”字符宽以匹配您正在寻找的内容,那么您可能处于良好状态。

因此,话虽如此,我会考虑转换中记录的“已删除”状态。您还可以通过首先执行以下操作来测试您的 VFP 端查询...

设置删除

做剩下的 var 和查询。

使用 DELETED ON,您将“忽略”任何已删除的记录。

于 2013-09-08T19:20:08.047 回答
1

在您的过滤器中有一个基于日期的过滤。当您需要过滤日期(日期时间)时,您不应该在 SQL Server 中使用 between() 或 Between。这是错误的来源,您可能会错过应该在选择列表中的记录,或者您可能会获得比您应该看到的更多的记录(因为无法使用“介于”来正确定义日期时间范围)。

您还应该记住,在 SQL Server 中,您的值可能是日期时间值,而您可能在 VFP 中使用了日期。确保您选择相同的范围。

考虑这种情况:

您有销售,其中 saleTime 表示销售发生的日期时间。您想获得 2013 年 1 月的所有销售额,您怎么能用 between 来写呢?没门。

设置@dateStart = '2013/1/1' 设置@dateEnd = ???

如果您将 @dateEnd: - 设置为“2013/2/1”,那么您可能会包含 2 月的销售额。- 到“2013/1/31”,那么您可能会错过当月最后一天的销售 - 到“2013/1/31 23:59:59.xxx”,那么您可能会错过最后一天的一些销售(机会很小,但它发生并且 SQL 服务器对 3 毫秒分辨率敏感)。

正确的方法是不要使用 BETWEEN 并将 dateEnd 设置为大于所需最大时间的最小时间IOW 正确获得 2013 年 1 月:

set @dateStart = '2013/1/1' set @dateEnd = '2013/2/1' -- 表示 2013 年 2 月 1 日 00:00:00。我们要排除的最短时间

select ... from ... where saleTime >= @dateStart and saleTime < @dateEnd

是具有日期时间范围的正确查询。

于 2013-09-24T19:36:06.503 回答