将FoxPro的SQL代码转换为SQL Server代码

时间:2013-09-08 17:09:40

标签: sql translation foxpro visual-foxpro

我正在尝试将一些代码从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”作为float数据类型存储在dbf中。

2 个答案:

答案 0 :(得分:2)

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

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

现在,有些事情并不是“完全”VFP如何处理事情,但基于概率,我认为你没关系,这与VFP中的“$”有关。 “$”用来表示右侧字符串中左侧的东西......

lcZnak1 = "HM,P6";

WHERE (Zakslozkap.SW $ lcZnak1)

转换为

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

可能没问题,但这是差异

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

所以,所有这一切,我会考虑转换记录的“删除”状态。您还可以通过首先执行以下操作来测试您的VFP端查询...

SET DELETED ON

执行var的其余部分并查询。

DELETED ON,您正在“忽略”任何已删除的记录。

答案 1 :(得分:1)

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

此外,您应该记住,在SQL服务器中,您可能在VFP中使用日期时,您的值是日期时间值。确保选择相同的范围。

考虑这种情况:

您有销售,其中saleTime表示销售发生的日期时间。您希望获得2013年1月的所有销售,您如何使用两者之间进行编写?没办法。

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

如果你设置@dateEnd: - 到'2013/2/1'那么你可能包括2月份的销售。 - 到'2013/1/31'那么很可能你在一个月的最后一天错过了销售 - 到'2013/1/31 23:59:59.xxx'然后你可能会错过最后一天的销售(很小的机会,但它发生了,SQL服务器的敏感度低至3毫秒)。

正确的方法是不使用BETWEEN并将dateEnd设置为最大时间更大时间,而不是所需的最长时间。我想正确地获得2013年1月:

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

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

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