Главная страница  Карта сайта  Печать  Написать письмо  RSS
Войти
Кнопка открытия главного меню
Персональный сайт
Стеллецкого Владимира
Обновлено: 19.02.2025 г.

Примеры с SQL

« первая   ‹ предыдущая   1   2   3   4   ›  »

Округление при дробных вычислениях (19.08.2009) #

Вчера наткнулся на неожиданное для меня поведение MS SQL 2005. Задача была простая: из суммы выделить размер НДС. И хотя я знаю, что чисто математически эта задача неразрешима, но что поделаешь сказали надо. Пишу запрос:

  1. SELECT 24000 * (1 - 1 / 1.18) as NDS   

И получаю значение 3661,032, которое немного (на несколько копеек) не сходится со значением, посчитанным на калькуляторе – 3661,016949. После некоторых экспериментов выяснилось, что MS SQL округляет значение коэффициента 1 / 1.18 до 6 знаков после запятой, и похоже что с бухгалтерским округлением. То есть получается 0,847457 вместо 0,84745762711, что при больших суммах даёт приличную погрешность.

Решить удалось чётким указанием типа, так:

  1. SELECT 24000 * (1 - CAST(1 as NUMERIC(15,8))/CAST(1.18 as NUMERIC(15,8))) as NDS  

Или:

  1. SELECT 24000 * (1 - 1/CAST(1.18 as NUMERIC(15,8))) as NDS    

Или так:

  1. DECLARE  @i NUMERIC (15, 8), @n NUMERIC (15, 8)  
  2. SELECT @i = 1, @n = 1.18  
  3. SELECT 24000 * (@i - @i / @n) as NDS   

Комментарии

swi, www (05.02.2009)
А почему не SELECT (24000 - 24000 / 1.18) as NDS ???
Потому, что 24000 это для примера, а на деле сумма вычисляется запросом. Мне показалось, что разницы быть не должно, ан нет. Математика тут не работает, поэтому и написал это сообщение.
swi, www (05.02.2009)
тогда можно:
SELECT @s=24000
SELECT (@s - @s / 1.18)
Здесь нет умножения на приближённое число
Да можно, но такой вариант не подойдёт для вычисления сумм для нескольких строк.

Проверка ОКПО (01.12.2008) #

Функция для проверки контрольного разряда кода ОКПО. Проверяются как 8-ми, так и 10-ти значные коды, при необходимости автоматически добавляются ведущие нули. Если ОКПО правильный, то функция возвращает 0, иначе 1.

  1. CREATE FUNCTION dbo.Check_OKPO (@OKPO VARCHAR(11))  
  2. RETURNS INT  
  3. AS  
  4. BEGIN  
  5.   DECLARE @I INT, @S INT, @SUMMA INT  
  6.   SET @OKPO = LTRIM(RTRIM(@OKPO))  
  7.   IF (@OKPO IS NULL OR @OKPO = ''RETURN(1)  
  8.   IF LEN(@OKPO) < 8   
  9.     SET @OKPO = RIGHT('00000000' + @OKPO, 8)  
  10.   IF LEN(@OKPO) > 8   
  11.     SET @OKPO = RIGHT('00' + @OKPO, 10)  
  12.   SET @I = 1  
  13.   SET @SUMMA = 0  
  14.   WHILE @I < LEN(@OKPO)  
  15.   BEGIN  
  16.     SET @SUMMA = @SUMMA + CAST(SUBSTRING(@OKPO, @I, 1) AS INT) * @I  
  17.     SET @I = @I + 1  
  18.   END  
  19.   SET @S = @SUMMA % 11  
  20.   IF @S = 10 SET @S = 0  
  21.   IF @S <> CAST(RIGHT(@OKPO, 1) AS INTRETURN(1)  
  22.   RETURN(0)  
  23. END  

Преобразование даты и времени в дату (05.03.2009) #

  1. SELECT CAST(FLOOR(CAST(GetDate() as float)) as Datetime)  

UPD: Недавно наткнулся на другое решение:

  1. -- Округлить дату  
  2. declare @date datetime  
  3. set @date=CONVERT(varchar(8), GETDATE(), 112)  
  4. -- Изъять время из даты  
  5. declare @time datetime  
  6. set @time=CONVERT(varchar(8), GETDATE(), 108)  

Комментарии

Мой комментарий (09.09.2010)
Недавно выяснил, что MS SQL 2008 поддерживает более простое решение этой проблемы:
  1. SELECT CAST(GETDATE() as DATE)  

Trim всех полей в БД (07.03.2008) #

  1. -- Trim всех полей в БД  
  2. DECLARE @tName varchar(1000), @cName varchar(1000)  
  3. DECLARE cur CURSOR FOR  
  4. SELECT c.TABLE_NAME,  
  5.        c.COLUMN_NAME  
  6. FROM INFORMATION_SCHEMA.COLUMNS c  
  7.      JOIN INFORMATION_SCHEMA.TABLES t ON c.TABLE_CATALOG = t.TABLE_CATALOG AND  
  8.      c.TABLE_SCHEMA = t.TABLE_SCHEMA AND c.TABLE_NAME = t.TABLE_NAME  
  9. WHERE t.TABLE_TYPE = 'BASE TABLE' AND -- исключаем View  
  10.       DATA_TYPE = 'varchar' AND       -- выбираем только текстовые поля  
  11.       NOT c.TABLE_NAME LIKE '%_OLD'   -- если надо ограничение на обрабатываемые таблицы  
  12. order by c.TABLE_NAME,  
  13.          c.COLUMN_NAME  
  14. OPEN cur  
  15.   
  16. FETCH NEXT FROM cur INTO @tName, @cName  
  17.        
  18. WHILE @@FETCH_STATUS = 0  
  19. BEGIN  
  20.   exec ('UPDATE ['+@tName+'] SET "'+@cName+'"=LTRIM(RTRIM("'+@cName+'"))')  
  21.   FETCH NEXT FROM cur INTO @tName, @cName  
  22. END  
  23.   
  24. CLOSE cur  
  25. DEALLOCATE cur  

Количество строк во ВСЕХ таблицах (22.02.2008) #

  1. -- Количество строк во ВСЕХ таблицах  
  2. create table #svv_tab_row_Count (ID int IDENTITY not nullName varchar(100), col int)  
  3. declare @i int, @j int  
  4. declare @t varchar(100)  
  5. insert into #svv_tab_row_Count (Name)  
  6. select Table_Name from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='dbo' and TABLE_TYPE='BASE TABLE'  
  7. SET @i = 1  
  8. SET @j = 1  
  9. WHILE (@j < 2)  
  10. BEGIN  
  11.  IF NOT EXISTS(select * from #svv_tab_row_Count where ID=@i) SET @j = 2  
  12.  ELSE  
  13.  BEGIN  
  14.     select @t = Name from #svv_tab_row_Count where ID=@i  
  15.   exec ('update #svv_tab_row_Count set col=(select Count(*) from ['+@t+']) where id='+@i+'')  
  16.  end  
  17.  SET @i = @i + 1  
  18. END  
  19. select * from #svv_tab_row_Count  
  20. drop table #svv_tab_row_Count  

UPD: Обновил данный запрос - добавил информацию по размеру данных и индексов, их сумму и отношение (подробнее здесь)

Список пользовательских баз данных (21.03.2007) #

Часто, при разработке приложений возникает необходимость предоставить возможность выбора базы данных. При этом будет красиво, если в списке не будет системных и отключенных (остановленных) баз. Со вторым все очень просто: в статусе проверяем нужный бит на наличие, и если он установлен, то база остановлена (первое условие в примере). А вот определения именно системности базы я не нашел. Поэтому предлагаются следующие решения (для второго условия):

  • Проверять поле sid - здесь кодируется владелец (Owner) базы, так вот для пользователя sa он равен 1. У нас только системные таблицы имеют пользователя sa, поэтому это решение нам подошло.
  • Проверять поле dbid - идентификатор базы, для несистемных он более 5 (на нашем сервере), Думаю на других тоже. Так что выбирайте, что больше нравится.
  • Исключить системные базы по именам. Мне этот подход совсем не нравится.

Я знаю, что в Books-OnLine рекомендуют пользоваться INFORMATION_SCHEMA, а не прямым обращением в системные таблицы, но в данном случае INFORMATION_SCHEMA.SCHEMATA работает скажем так "странно".
Поэтому решение было выбрано такое:

  1. SELECT * FROM sysdatabases WHERE status&100000=0 AND sid<>1 ORDER BY name  

Цикл в SQL-запросе (07.11.2006) #

Цикл один из методов наглядной проверки скорости выполнения SQL-запроса. Лучше, конечно, использовать Profiler или анализировать план выполнения, но часто быстрее и проще "наглядная проверка". Итак, имеем два запроса. Надо определить какой из них предпочтительнее по скорости выполнения. Пишем два цикла в каждом, по одному запросу. Прогоняем каждый два-три раза и определяем среднюю скорость выполнения. Где меньше время, тот и быстрее, хотя не факт, что лучше. Количество выполнений запросов в цикле следует подбирать таким, чтобы время выполнения было около 20 секунд.

  1. DECLARE @i INT  
  2. SET @i = 1  
  3.   
  4. WHILE (@i < 500)  
  5. BEGIN  
  6. // здесь пишется выполняемый в цикле код  
  7. SET @i = @i + 1  
  8. END  

Даты в SQL-запросах (10.10.2006) #

  1. ADOQuery1.Close;  
  2. ADOQuery1.SQL.Text:='SELECT * FROM TAB1 WHERE DATE>='+  
  3.                     QuotedStr(FormatDateTime('yyyy-mm-dd 00:00:00', dtpFrom.Date))+  
  4.                     ' AND DATE<='+  
  5.                     QuotedStr(FormatDateTime('yyyy-mm-dd 23:59:59', dtpTo.Date));  
  6. ADOQuery1.Open;  

Часто в SQL-запросах необходимо сделать выборку по дате, и тут многие сталкивались, наверное, с проблемой что по разному настроенные MS SQL сервера "ожидают" дату в немного разном формате. Я в своих программах использую выше приведённый пример, и с проблемами пока не сталкивался.
dtpFrom и dtpTo это компоненты типа TDateTimePicker с датой начала периода и конца периода соответственно.

Многопользовательский доступ к таблицам MSSQL (07.10.2006) #

Часто необходимо обеспечить возможность выбора строк из Таблицы MS SQL при многопользовательской работе. Т.е. первый редактирует в транзакции, а второй в это время читает предыдущий вариант.

  1. ADOQuery1.Connection.IsolationLevel := ilReadUncommitted;  
  2. ADOQuery1.Connection.Execute('SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED');  
  3. ADOQuery1.SQL.Text:='...';  
  4. ADOQuery1.Open;  

« первая   ‹ предыдущая   1   2   3   4   ›  »

  Вы 58 524 посетитель этой странички
с 07 октября 2006 года
© http://svv-home.ru
О сайте