2013-09-08 1 views
1

Я пытаюсь перевести немного кода из FoxPro на SQL Server, и я столкнулся с очень странным поведением.Перевести код SQL-кода 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.

Итак, есть разница в 100 тыс. И потому что речь идет о деньгах, это много. Я отчаянно ищу решение, поэтому я прошу. Является ли мой перевод SQL точно отражением кода от FoxPro?

Столы одинаковые, поэтому данные. В SQL я использую связанный сервер для доступа к этим dbfs. Поле «koruny» хранится в dbf как тип данных float.

+0

Какие два запроса возвращаются сами по себе? У них одинаковый набор результатов? Я имею в виду два полных оператора 'select'. – BellevueBob

ответ

2

Если кто-то преобразовал данные с VFP на SQL-сервер, мне интересно, есть ли записи, помеченные для удаления в VFP, которые НЕ были загружены на SQL-сервер. Это выполняется в VFP, используя «SET DELETED ON», чтобы скрыть записи, помеченные для удаления. «SET DELETED OFF», чтобы ПОЗВОЛИ удалить удаленные записи, которые будут отображаться (и в конечном итоге включены в запрос, который у вас есть).

Таким образом, я бы затем подтвердил COUNT записей, обрабатываемых в вашем запросе, проверив @@ rowcount из SQL, чтобы узнать, совпадает ли он.

Теперь есть некоторые вещи, которые не являются «точными», как VFP делает вещи, но исходя из вероятности, я думаю, что вы в порядке, и это касается «$» в VFP. «$» Используется, чтобы сказать это то, на левой стороне ANYWHERE в строке справа ...

lcZnak1 = "HM,P6"; 

WHERE (Zakslozkap.SW $ lcZnak1) 

ваш переход к

где p.SW = «HM» или. SW = «P6»

, вероятно, хорошо, но вот разница

Допустим, у вас есть значение в столбце «SW» на «М» или «Р», или даже «М, «или« P »или даже« HM, P »,« HM »,«, P6 »и т. д. ВСЕ из них будут квалифицироваться. Это почти как команда LIKE в SQL. Точно так же в ваших суммированиях внизу. Но если ваши столбцы имеют символы «x» в широком соответствии с тем, что вы ищете, вы, вероятно, в хорошей форме.

Итак, все, что было сказано, я бы рассмотрел статус «УДАЛИТЬ» записей из конверсии. Вы также можете проверить свой VFP стороны запрос просто, выполнив следующие действия первого ...

SET DELETED ON

Do остальной часть вашего вара и запросов.

с DELETED ON, вы «НЕИСПРАВЛЯЕТ» любые удаленные записи.

1

В фильтрах есть фильтрация по дате. Когда вам нужно отфильтровать даты (datetimes), вы не должны использовать между() или Between на SQL-сервере.Это источник ошибок, и есть вероятность, что вы пропустите записи, которые должны быть в списке выбора, или вы можете получить больше записей, чем вы должны видеть (потому что нет возможности правильно определить диапазон datetime, используя «между»).

Также вы должны иметь в виду, что, вероятно, на сервере SQL ваши значения являются значениями даты и времени, в то время как вы могли использовать дату в VFP. Убедитесь, что вы выбираете один и тот же диапазон.

Рассмотрим этот случай:

У вас есть продажи, где saleTime представляет DateTime продажа произошло. Вы хотите получить все продажи, которые были сделаны в январе 2013 года, как вы могли написать, что используете между ними? Ни за что.

set @dateStart = '2013/1/1' set @dateEnd = ???

Если вы установили @dateEnd: - to '2013/2/1, то вы можете включить продажи с февраля. - до '2013/1/31', то вам наверняка не хватают продаж в последний день месяца - до '2013/1/31 23: 59: 59.xxx', тогда вы можете пропустить некоторые продажи в последний день (тонкий но это происходит, и SQL-сервер чувствителен до разрешения 3 мс).

Правильный способ не использовать BETWEEN и установить dateEnd ко времени минимум, который больше чем желаемая максимальное время. IOW, чтобы получить январь 2013 года правильно:

set @dateStart = '2013/1/1' set @dateEnd = '2013/2/1' - означает 1 февраля 2013 00:00:00. Минимальное время, которое мы хотим исключить

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

- правильный запрос с диапазоном дат-времени.