Конференция "Базы" » Нужно упростить запрос [MSSQL]
 
  • Ольга © (07.07.09 11:22) [0]
    В таблице есть поле float. В запросе это поле нужно представить в виде двух натуральных чисел - целая и дробная части без округлений.
    Делаю с помощью строковых функций - получилась громоздкая конструкция. Уверена, что можно сделать проще, не могу найти как.

    IF object_id('tempdb..#tmp') is not null DROP TABLE #tmp
    CREATE TABLE #tmp(val2 float)
    INSERT INTO #tmp VALUES (-956.5)

    SELECT  ABS(cast(CASE WHEN CHARINDEX('.',cast(val2 as varchar(20)))>0
     THEN substring(cast(val2 as varchar(20)),1,CHARINDEX('.',cast(val2 as varchar(20)))-1)
     ELSE NULL END as int)),
        cast(CASE WHEN CHARINDEX('.',cast(val2 as varchar(20)))>0
     THEN substring(cast(val2 as varchar(20)),CHARINDEX('.',cast(val2 as varchar(20)))+1,2)
     ELSE NULL END as int)
    FROM #tmp
  • Ega23 © (07.07.09 11:26) [1]
    Я бы в numeric сначала попробовал скастовать, а дальше уже с ним игрался бы.
  • MsGuns © (07.07.09 11:43) [2]
    А зачем понадобилась дробная часть плавающего числа как целое БЕЗ ОКРУГЛЕНИЯ ?
  • Ольга © (07.07.09 11:54) [3]

    > А зачем понадобилась дробная часть плавающего числа как
    > целое БЕЗ ОКРУГЛЕНИЯ

    Так у заказчика хранятся данные (таблица создана до рождения Билла Гейтса): целая часть - количество "табуреток", дробная - количество "валенок". Делаю нормальную БД, нужно перенести данные.
  • Кщд (07.07.09 11:54) [4]
    >Ольга ©   (07.07.09 11:22)  
    floor, round, ceiling не работают?
  • Ольга © (07.07.09 11:59) [5]

    > floor, round, ceiling не работают?

    Эти функции округляют: 956.5 -> 957  5
  • Anatoly Podgoretsky © (07.07.09 12:13) [6]
    > Ольга  (07.07.2009 11:54:03)  [3]

    Вероятнее всего получишь 0.33333 валенка
  • Anatoly Podgoretsky © (07.07.09 12:15) [7]
    > Ольга  (07.07.2009 11:59:05)  [5]

    Зато 956.5 - Int(Num) не округляют
  • Anatoly Podgoretsky © (07.07.09 12:16) [8]
    > Ольга  (07.07.2009 11:54:03)  [3]

    Я вообще много чудес видел, но данный заказчик всех переплюнул.
  • Кщд (07.07.09 12:16) [9]
    >Ольга ©   (07.07.09 11:59) [5]
    ну, а если подумать, то нечто вроде:
    round(x - 0.5)
  • Ega23 © (07.07.09 12:17) [10]

    > ну, а если подумать, то нечто вроде:
    > round(x - 0.5)


    Не факт.
  • Кщд (07.07.09 12:20) [11]
    >Ega23 ©   (07.07.09 12:17) [10]
    тогда строго из BOL:
    SELECT ROUND(150.75, 0, 1);
    GO
  • Ольга © (07.07.09 12:26) [12]
    Попробовала с numeric - стало еще хуже, в дробной части незначимые нули.

    > SELECT ROUND(150.75, 0, 1);

    А вот это вроде то, что надо (до последней строчки мануала не дочитала)
  • Ольга © (07.07.09 12:53) [13]
    И так, табуретки теперь преобразовываются просто. А с "валенками" не получается:

    IF object_id('tempdb..#tmp') is not null DROP TABLE #tmp
    CREATE TABLE #tmp(val2 float)
    INSERT INTO #tmp VALUES (-956.5)
    INSERT INTO #tmp VALUES (959.49)

    SELECT ABS(cast(ROUND(val2,0,1) as int)),
          cast(CASE WHEN CHARINDEX('.',cast(val2 as varchar(20)))>0
      THEN substring(cast(val2 as varchar(20)),CHARINDEX('.',cast(val2 as varchar(20)))+1,2)
      ELSE NULL END as int)
    FROM #tmp  ELSE NULL END as int)


    Есть еще идеи? Это мне нужно не из любви к искусству, количество "валенок" нужно несколько раз использовать в предлжении WHERE
  • ANB (07.07.09 13:04) [14]

    > количество "валенок" нужно несколько раз использовать в
    > предлжении WHERE

    сделай вложенный запрос и не парься.
  • Кщд (07.07.09 13:48) [15]
    >Ольга ©   (07.07.09 12:53) [13]
    >CHARINDEX('.'
    в MS SQL разделитель не зависит от локали?)

    если абстрактно, то:
    целая часть: ABS(cast(ROUND(val2,0,1) as int))
    => дробная: frac = abs(val2) - ABS(cast(ROUND(val2,0,1) as int))
    => искомое int2 = cast(frac * power(10, len(cast(frac as varchar(20)))-2) as int)
  • Вариант (07.07.09 14:11) [16]

    > Ольга ©   (07.07.09 12:53) [13]


    Поиграй с запросом

    DECLARE @N  float;
    SET @N=-750.158;

    select ROUND(@N,0,1) as C,ROUND(@N-ROUND(@N,0,1),3) as FR


    А если и дробную часть надо как целую, то почему бы ее не умножить... на 10 или 100 или 1000  или сколько знаков дробной там надо учесть прямо в запросе?
  • topS (07.07.09 14:36) [17]
    > Ольга ©   (07.07.09 11:54) [3]
    > ...целая часть - количество "табуреток", дробная - количество "валенок".

    0.1 это сколько валенок, 1 или 10? а может быть 1000000?
  • Кщд (07.07.09 14:53) [18]
    >topS   (07.07.09 14:36) [17]

    >дробная - количество "валенок".
  • topS (07.07.09 15:02) [19]

    > Кщд   (07.07.09 14:53) [18]

    кому нужны ошметки валенок?
  • Anatoly Podgoretsky © (07.07.09 15:58) [20]
    > Вариант  (07.07.2009 14:11:16)  [16]

    Умножить можно, но не известно на сколько.
  • Кщд (08.07.09 05:42) [21]
    >topS   (07.07.09 15:02) [19]
    как они хранят десять валенок(ов?) - мне неведомо
    если подходить строго математически, то сказано было четко - дробная часть их(валенок) кол-во

    >Вариант   (07.07.09 14:11) [16]
    не читатель?
  • Вариант (08.07.09 07:26) [22]

    > Кщд   (08.07.09 05:42) [21]

    Писатель?


    > Anatoly Podgoretsky ©   (07.07.09 15:58) [20]


    Понятно, если это так. Но я вижу код
    > Ольга ©   (07.07.09 12:53) [13]


    substring(cast(val2 as varchar(20)),CHARINDEX('.',cast(val2 as varchar(20)))+1,2)

    , где после запятой берется 2 символа - то есть количество вроде как от 0 до 99. Умножить на 100 в этом случае... А будет до 1000, ну будут умножать на 1000 и т.д.
    Хотя в общем согласен с
    >  Anatoly Podgoretsky ©   (07.07.09 12:16) [8]
  • Кщд (08.07.09 08:27) [23]
    >Вариант   (08.07.09 07:26) [22]
    ветку-то недосуг прочитать перед тем, как постить?

    >substring(cast(val2 as varchar(20)),CHARINDEX('.',cast(val2 as >varchar(20)))+1,2)
    в MS SQL разделитель не зависит от локали?
  • Ольга © (08.07.09 09:03) [24]

    > в MS SQL разделитель не зависит от локали?

    Данные хранятся с точкой. Запятая используется только для отображения (в зависимости от локали).


    > substring(cast(val2 as varchar(20)),CHARINDEX('.',cast(val2
    > as varchar(20)))+1,2) , где после запятой берется 2 символа
    > - то есть количество вроде как от 0 до 99

    Да, здесь моя ошибка. Я не знаю сколькозначная цифра может встретиться после запятой (двойку поставила, визуально оценив несколько страниц - вроде цифры маленькие). Пример в [15] работает правильнее, хоть и выраженьице получается тоже не особо удобоваримое, ну да бог с ним, SQL-сервер переварит.


    > сделай вложенный запрос и не парься

    Попыталась, запарилась. Запрос из одной таблицы. Даже если объединить ее саму с собой, все равно во WHERE нужна связка по табуреткам и валенкам. Или я не поняла идеи.

    Привожу окончательный код:

    IF object_id('tempdb..#tmp') is not null DROP TABLE #tmp
    CREATE TABLE #tmp(val2 float)
    INSERT INTO #tmp VALUES (-956.5)
    INSERT INTO #tmp VALUES (959.449)

    SELECT ABS(cast(ROUND(val2,0,1) as int)),
          cast((abs(val2) - ABS(cast(ROUND(val2,0,1) as int))) * power(10, len(cast(abs(val2) -
          ABS(cast(ROUND(val2,0,1) as int)) as varchar(20)))-2) as int)
    FROM #tmp
    WHERE cast((abs(val2) - ABS(cast(ROUND(val2,0,1) as int))) * power(10, len(cast(abs(val2) -
         ABS(cast(ROUND(val2,0,1) as int)) as varchar(20)))-2) as int) BETWEEN 1 AND 10
         OR
         cast((abs(val2) - ABS(cast(ROUND(val2,0,1) as int))) * power(10, len(cast(abs(val2) -
         ABS(cast(ROUND(val2,0,1) as int)) as varchar(20)))-2) as int) > 50


    Всем огромное спасибо за помощь!
  • Anatoly Podgoretsky © (08.07.09 09:13) [25]
    > Ольга  (08.07.2009 09:03:24)  [24]

    Ответь на вопрос, как точно хранится 1 валенок и 10 валенок
  • topS (08.07.09 09:16) [26]

    > Ольга ©   (08.07.09 09:03) [24]

    и всё же, почему вдруг -956.5 это 5 валенок, а не 500?
    и как 'изобразить' эти самые 500 валенок?
    и почему устраивает, если 959.499999 это 499999 валенка, а 959.4999999 это 4 валенка?
  • Вариант (08.07.09 09:19) [27]

    > Кщд   (08.07.09 08:27) [23]

    иии ??? Я где-то об этом упоминал?

    Наверное ты хочешь сказать, что твой вариант единственно верный и нужный? С уважением к твоим знаниям и не собираясь отнять лавры первого помогшего, я просто привел свой вариант, без длинных cast. И даже не полный вариант, а только как "подумать" для автора вопроса. Ей понравился твой - я рад за тебя.


    > Ольга ©   (08.07.09 09:03) [24]


    > Да, здесь моя ошибка. Я не знаю сколькозначная цифра может
    > встретиться после запятой

    Тогда задача не решаема. Или надо передавать хотя бы количество значащих цифр параметром в запрос.
  • Вариант (08.07.09 09:23) [28]

    > Вариант   (08.07.09 09:19) [27]


    Хотя правильней - это знать ответы на вопросы

    > Anatoly Podgoretsky ©   (08.07.09 09:13) [25]


    > topS   (08.07.09 09:16) [26]
  • Anatoly Podgoretsky © (08.07.09 09:33) [29]
    Задача имеет решение только для чисел не оканчивающихся на НОЛЬ и то частичное, поскольку float имеет относительную точность и абсолютное большинство чисел можно представить только приблизительно.
    Следует также добавить, что любые операции с числами меняют эту точность.
  • Anatoly Podgoretsky © (08.07.09 09:34) [30]

    > Так у заказчика хранятся данные (таблица создана до рождения
    > Билла Гейтса): целая часть - количество "табуреток", дробная
    > - количество "валенок". Делаю нормальную БД, нужно перенести
    > данные.

    Если у заказчика есть бумажная база, то надо просто заставить ввести валенки вручную
  • Кщд (08.07.09 09:42) [31]
    >Вариант   (08.07.09 09:19) [27]
    какие лавры?
    о чем Вы?)
    >Кщд   (07.07.09 12:20) [11]
  • Вариант (08.07.09 10:20) [32]

    > Кщд   (08.07.09 09:42) [31]

    Значит я не понял о чем ты. Задай вопрос еще раз, только что бы мне не пришлось угадывать смысл, есть какие-то замечания -напиши, аргументируй - отвечу.
  • Ольга © (08.07.09 13:37) [33]
    В эту таблицу пишет некий фортрановский модуль, и пишет аккуратно (видимо с округлением). Так что цифр с периодом в дробной части в ней нет.
    956.5   - 5 валенков
    956.50 - 50 валенков
    Если встретится 0.4999 - видимо, будет 4999 валенков (но такого пока не встречалось).

    > Если у заказчика есть бумажная база, то надо просто заставить
    > ввести валенки вручную

    Нашего Заказчика замучаешься заставлять... А вот бабок за эту работу можно неплохо срубить :)
  • Ольга © (08.07.09 13:51) [34]

    > 956.50 - 50 валенков

    Написала это пример с потолка, потом поняла, что во float .50  не записать.
    Народ, каюсь - все остальные поля, коих немерено в этой таблице, float, а одно это поле sql_variant. Простите, что ввела в заблуждение.
  • Anatoly Podgoretsky © (08.07.09 13:59) [35]
    > Ольга  (08.07.2009 13:37:33)  [33]

    Для чисел, что ,5 что ,5000 это одно и тоже и нельзя различить. Существует вариант прямой, извращеной записи прямо в файл таблицы, но это врядли, вероятнее это поле не Float/Number
  • Вариант (08.07.09 14:09) [36]

    > Ольга ©   (08.07.09 13:51) [34]

    "Просто хочется рвать и метать!" (c) Бывалов из х/ф "Волга-Волга" :-)
  • Ольга © (08.07.09 14:11) [37]

    > Вариант   (08.07.09 14:09) [36]

    Посыпаю голову пеплом...
  • Anatoly Podgoretsky © (08.07.09 14:16) [38]
    > Ольга  (08.07.2009 13:51:34)  [34]

    Тогда хуже, поскольку там может быть что угодно, включая пользовательские типы.
  • Anatoly Podgoretsky © (08.07.09 14:24) [39]

    > Так у заказчика хранятся данные (таблица создана до рождения
    > Билла Гейтса): целая часть - количество "табуреток", дробная
    > - количество "валенок". Делаю нормальную БД, нужно перенести
    > данные.

    И вряд ли это из-за низкой квалификации, судя по последним данным квалификация высокая.
  • Ольга © (08.07.09 14:30) [40]

    > Тогда хуже, поскольку там может быть что угодно, включая
    > пользовательские типы.

    "Там" это где? Это "кривенькое" поле мы разобрали по косточкам, информация в нем однородная... Каких сюрпризов можно ждать?
  • clickmaker © (08.07.09 14:35) [41]
    в запросе в [0] слишком много вызовов CHARINDEX.
    Я бы курсором прошелся по таблице
  • Ольга © (08.07.09 14:52) [42]
    Запрос в [0] и есть попытка создать курсор. "Табуретки" и "валенки" входят в состав естественного первичного ключа, которого реально в таблице нет. Вот я и хочу создать курсор, после чего N раз прогнать через него эту же таблицу, расфасовывая информацию в новую базу.
  • Anatoly Podgoretsky © (09.07.09 08:49) [43]

    > "Там" это где? Это "кривенькое" поле мы разобрали по косточкам,
    >  информация в нем однородная... Каких сюрпризов можно ждать?
    >

    В sql_variant = можно хранить, что угодно, даже пользовательские типы.
    И для разборки надо знать формат. Поддержка ложится на пользователя, а не на сервер.
  • amir (09.07.09 16:37) [44]
    Попробую пожелиться некоторым опытом. На новой (уже старой :)) работе столкнулся с древним (ЕС-м) представлением чисел в базе в символьном виде. Т.е. есть таблица, в одном из полей которой "сидят" строки по 8 символов-цифр без всяких точек. В другом поле - 6 символов-цифр и т.д. Никакой документации нетути. Последний программист, который сто-то там помнил, уволился лет 5 назад. В качестве "отправной" точки имеются только всевозможные ведомости, в которых, как правило, результаты вычислений, а не сами "числа", причем, ессно, числа дробные.
    Пока не залез в асмовские исходники и не посмотрел  как там выделяется дробная часть при вычислениях (если кто помнит - десятичная упакованная арифметика), не смог разобраться.

    ИМХО, это похоже на тот случай. Т.е. корректно разобраться где "валенки", а где "сапоги" без разбора программного кода невозможно.
 
Конференция "Базы" » Нужно упростить запрос [MSSQL]
Есть новые Нет новых   [134473   +31][b:0][p:0.002]