Конференция "Базы" » Получение остатков на каждую дату
 
  • xmen (24.11.10 19:44) [0]
    СУБД Oracle, в БД имеется таблица, в которой одно из полей дата и время, второе сумма операции, третье входящий остаток.

    Возможно ли одним запросом получить список входящих остатков на начало каждой из дат, т.е. в одном дне несколько записей имеющих разное время, соответственно остаок на начало имеет наименьшее время.

    на выходе нужен список из пар: дата и время, входящий остаток.
  • Игорь Шевченко © (24.11.10 20:25) [1]
    Возможно, с использованием аналитических функций.
  • Игорь Шевченко © (24.11.10 20:36) [2]
    Или я что-то не понял или без аналитики где-то так:

    WITH foo AS (
     SELECT TO_DATE('01.01.2000 01:00','dd.mm.yyyy hh24:mi') your_date, 1 rem FROM dual
     UNION ALL
     SELECT TO_DATE('01.01.2000 02:00','dd.mm.yyyy hh24:mi') your_date, 2 rem FROM dual
     UNION ALL
     SELECT TO_DATE('02.01.2000 01:00','dd.mm.yyyy hh24:mi') your_date, 4 rem FROM dual
     UNION ALL
     SELECT TO_DATE('02.01.2000 02:00','dd.mm.yyyy hh24:mi') your_date, 6 rem FROM dual
    )
    SELECT TRUNC(your_date), MIN(rem) FROM foo
     GROUP BY TRUNC(your_date);

  • Inovet © (24.11.10 22:18) [3]
    > [2] Игорь Шевченко ©   (24.11.10 20:36)
    > SELECT TRUNC(your_date), MIN(rem) FROM foo
    > GROUP BY TRUNC(your_date);

    Наверно как-то так надо, потому что MIN(rem) вряд ли правильно

    SELECT your_date, rem
    FROM tbl t LEFT JOIN (
     SELECT MIN(your_date)
     FROM tbl
     GROUP BY TRUNC(your_date)
    ) tm ON t.your_date = tm.your_date
    ;

  • Игорь Шевченко © (24.11.10 23:47) [4]

    > потому что MIN(rem) вряд ли правильно


    Значит через аналитику.

    WITH foo AS (
    SELECT TO_DATE('01.01.2000 01:00','dd.mm.yyyy hh24:mi') your_date, 2 rem FROM dual
    UNION ALL
    SELECT TO_DATE('01.01.2000 02:00','dd.mm.yyyy hh24:mi') your_date, 1 rem FROM dual
    UNION ALL
    SELECT TO_DATE('02.01.2000 00:30','dd.mm.yyyy hh24:mi') your_date, 4 rem FROM dual
    UNION ALL
    SELECT TO_DATE('02.01.2000 02:00','dd.mm.yyyy hh24:mi') your_date, 6 rem FROM dual
    )
    SELECT your_date,rem FROM foo
     WHERE your_date IN (SELECT DISTINCT MIN(your_date) OVER (PARTITION BY TRUNC(your_date)) FROM foo)



    Вылезает
    01.01.2000 01:00, 2
    02.01.2000 00:30, 4
  • Кщд (25.11.10 10:34) [5]
    >Получение остатков на каждую дату

    WITH foo AS (
    SELECT TO_DATE('01.01.2000 01:00','dd.mm.yyyy hh24:mi') your_date, 2 rem FROM dual
    UNION ALL
    SELECT TO_DATE('01.01.2000 02:00','dd.mm.yyyy hh24:mi') your_date, 1 rem FROM dual
    UNION ALL
    SELECT TO_DATE('02.01.2000 00:30','dd.mm.yyyy hh24:mi') your_date, 4 rem FROM dual
    UNION ALL
    SELECT TO_DATE('02.01.2000 02:00','dd.mm.yyyy hh24:mi') your_date, 6 rem FROM dual
    )
    SELECT trunc(g.your_date),
          min(g.rem ) keep (dense_rank first order by g.your_date)
    FROM foo g
    GROUP BY trunc(g.your_date)

  • Кщд (25.11.10 11:16) [6]
    >Inovet ©   (24.11.10 22:18) [3]
    если нужно на КАЖДУЮ строку, то двойной FTS - самый последний вариант и можно делать так, как предлагал Игорь Шевченко - через аналитику:

    WITH foo AS (
    SELECT TO_DATE('01.01.2000 01:00','dd.mm.yyyy hh24:mi') your_date, 2 rem FROM dual
    UNION ALL
    SELECT TO_DATE('01.01.2000 02:00','dd.mm.yyyy hh24:mi') your_date, 1 rem FROM dual
    UNION ALL
    SELECT TO_DATE('02.01.2000 00:30','dd.mm.yyyy hh24:mi') your_date, 4 rem FROM dual
    UNION ALL
    SELECT TO_DATE('02.01.2000 02:00','dd.mm.yyyy hh24:mi') your_date, 6 rem FROM dual
    )
    SELECT g.your_date, g.rem,
         first_value(g.rem) over(partition by trunc(g.your_date) order by g.your_date)    
    FROM foo g
    order by g.your_date

  • Inovet © (25.11.10 16:09) [7]
    > [6] Кщд   (25.11.10 11:16)
    > если нужно на КАЖДУЮ строку, то двойной FTS - самый последний
    > вариант и можно делать так, как предлагал Игорь Шевченко
    > - через аналитику:

    Я особенносте Оракл не знаю, поэтому и написал "как-то так".
  • xmen (25.11.10 17:17) [8]
    Всем спасибо, попробую предложенные варианты.

    После того как запостил вопрос написал свое решение, оно почему-то очень громоздкое:

    Select SS.CID, SS.DayList,
    (Select Abs(C_4)
    From IBS.VW_CRIT_FULL_RECORDS
    Where Collection_Id = SS.CID And
    C_1 = TO_DATE(SS.MinTime, 'DD/MM/YYYY HH24:MI:SS') And
    RowNum <= 1) Ostatok
    From
    (Select Days.CID, Days.DayList,
    (Select To_Char(Min(C_1), 'DD/MM/YYYY HH24:MI:SS')
    From IBS.VW_CRIT_FULL_RECORDS
    Where (Collection_Id = Days.CID) And
    (C_1 >= TO_DATE(Days.DayList || ' 00:00:00', 'DD/MM/YYYY HH24:MI:SS')) And
    (C_1 <= TO_DATE(Days.DayList || ' 23:59:59', 'DD/MM/YYYY HH24:MI:SS'))
    ) MinTime
    From
    (Select Distinct CID, DL.DayList
    From
    (Select Collection_Id CID, TO_CHAR(C_1, 'DD/MM/YYYY') DayList
    From IBS.VW_CRIT_FULL_RECORDS
    Where (Collection_Id = '4290840243') And
    (C_1 >= TO_DATE('06/01/2010 00:00:00', 'DD/MM/YYYY HH24:MI:SS')) And
    (C_1 <= TO_DATE('24/11/2010 23:59:59', 'DD/MM/YYYY HH24:MI:SS'))
    ) DL
    ) Days
    ) SS



    в данной части на клиенте будут подставлены нужные значения
    Where (Collection_Id = '4290840243') And
    (C_1 >= TO_DATE('06/01/2010 00:00:00', 'DD/MM/YYYY HH24:MI:SS')) And
    (C_1 <= TO_DATE('24/11/2010 23:59:59', 'DD/MM/YYYY HH24:MI:SS'))

  • Кщд (26.11.10 07:42) [9]
    >xmen   (25.11.10 17:17) [8]
    1. трижды обращаетесь к одной и той же таблице;
    2. неаккуратно используете псевдонимы;
    3. лишние преобразования date-char-date - несмотря на то, что Вам в этой ветке рассказали о trunc
    4. с какой целью использован rownum?

    было бы отлично, если бы привели пример исходных данных(напр., Игорь Шевченко ©   (24.11.10 20:36) [2]) и тех, что нужно получить.
  • Кщд (26.11.10 08:03) [10]
    >Inovet ©   (25.11.10 16:09) [7]
    тот вариант, что предложили Вы, не просто не вернет нужного результата(т.е. это аналог select your_date, rem from tbl:)), но даже не будет выполняться
    не только на Oracle
  • xmen (26.11.10 10:22) [11]

    > >xmen   (25.11.10 17:17) [8]1. трижды обращаетесь к одной
    > и той же таблице;2. неаккуратно используете псевдонимы;3.
    >  лишние преобразования date-char-date - несмотря на то,
    > что Вам в этой ветке рассказали о trunc4. с какой целью
    > использован rownum?было бы отлично, если бы привели пример
    > исходных данных(напр., Игорь Шевченко ©   (24.11.10 20:36)
    > [2]) и тех, что нужно получить.


    Действительно трижды - так уж получилось :-)
    неаккуратно - поясните.
    что trunc используют видел, но во-первых я был не в курсе, что она делает, а во вторых написал свой "шедевр" немного раньше чем ответили на форуме.

    Исходные данные такие:

    Дата и время проводки Входящий остаток
    08.05.2010 08:39:16 -842783,49
    08.05.2010 08:39:16 -843337,66
    08.05.2010 23:59:59 -843483,49
    08.05.2010 23:59:59 -878531,31
    08.05.2010 23:59:59 -880921,31
    08.05.2010 23:59:59 -884204,83
    08.05.2010 23:59:59 -885710,53
    08.05.2010 23:59:59 -886010,53
    08.05.2010 23:59:59 -888010,53
    08.05.2010 23:59:59 -889010,53
    08.05.2010 23:59:59 -890010,53
    08.05.2010 23:59:59 -985010,53
    08.05.2010 23:59:59 -1032020,53
    08.05.2010 23:59:59 -1041030,53
    08.05.2010 23:59:59 -3343644,68
    08.05.2010 23:59:59 -3251024,68
    08.05.2010 23:59:59 -3231224,68
    08.05.2010 23:59:59 -3118431,91
    08.05.2010 23:59:59 -3118481,91
    08.05.2010 23:59:59 -3118531,91
    08.05.2010 23:59:59 -3118536,49
    08.05.2010 23:59:59 -3118561,91
    08.05.2010 23:59:59 -3118611,91
    08.05.2010 23:59:59 -3118677,58
    08.05.2010 23:59:59 -3118727,58
    08.05.2010 23:59:59 -3118777,58
    08.05.2010 23:59:59 -3118927,58
    08.05.2010 23:59:59 -3119077,58
    08.05.2010 23:59:59 -3119227,58
    08.05.2010 23:59:59 -3121227,58
    08.05.2010 23:59:59 -3123227,58
    08.05.2010 23:59:59 -3121727,58
    08.05.2010 23:59:59 -3120227,58
    08.05.2010 23:59:59 -3119227,58
    08.05.2010 23:59:59 -3116227,58
    08.05.2010 23:59:59 -3113227,58
    08.05.2010 23:59:59 -3110222,58
    08.05.2010 23:59:59 -3107534,58
    08.05.2010 23:59:59 -3105534,58
    08.05.2010 23:59:59 -3106034,58
    08.05.2010 23:59:59 -3105874,58
    08.05.2010 23:59:59 -3103874,58
    08.05.2010 23:59:59 -3096874,58
    08.05.2010 23:59:59 -3293124,58
    08.05.2010 23:59:59 -1293124,58

    В итоге нужно получить 08.05.2010 -842783,49
    Естественно в исходных данных дней гораздо больше.

    Изначально, в качестве примера мне показывали другие данные, где у каждой операции было свое время, но впоследствии оказалось, что операции могут быть проведены пакетно и тогда у них будет одно время, поэтому было добавлено rownum
  • Игорь Шевченко © (26.11.10 14:11) [12]
    решение из [2] никак ? заменив MIN на MAX
    Насколько я вижу, у тебя остаток все время уменьшается в течение одной даты.
  • Inovet © (26.11.10 20:41) [13]
    > [10] Кщд   (26.11.10 08:03)
    > [10] Кщд   (26.11.10 08:03)
    > тот вариант, что предложили Вы, не просто не вернет нужного
    > результата(т.е. это аналог select your_date, rem from tbl:
    > )), но даже не будет выполняться не только на Oracle

    Да. Вот так должен работать

    SELECT t.your_date, t.rem
    FROM tbl t JOIN (
    SELECT MIN(your_date) as your_date
    FROM tbl
    GROUP BY TRUNC(your_date)
    ) tm ON t.your_date = tm.your_date



    Судя по данным в
    > [11] xmen   (26.11.10 10:22)

    условие
    > [0] xmen   (24.11.10 19:44)
    > соответственно остаок на начало имеет наименьшее время

    невыполнимо, нет уникального признака, какая проводка была первой. Где здесь наименьшее время?

    > 08.05.2010 08:39:16 -842783,49
    > 08.05.2010 08:39:16 -843337,66
  • Кщд (29.11.10 08:46) [14]
    >xmen   (26.11.10 10:22) [11]
    >неаккуратно - поясните.
    нет псевдонимов у таблиц и полей - это чревато непредсказуемым результатом запроса

    по поводу rownum: т.е. Вам всё равно какой из двух остатков с одним и тем же временем брать?)
    пора бы задуматься об уникальном идентификаторе записи или - как минимум - сменить тип поля на timestamp

    >Дата и время проводки Входящий остаток
    >08.05.2010 08:39:16 -842783,49

    с такими данными неудобно работать
    >было бы отлично, если бы привели пример исходных данных(напр., >Игорь Шевченко ©   (24.11.10 20:36) [2]) и тех, что нужно получить.
  • Кщд (29.11.10 08:51) [15]
    >Inovet ©   (26.11.10 20:41) [13]

    >невыполнимо, нет уникального признака, какая проводка была первой. >Где здесь наименьшее время?
    абсолютно в точку)
    в этом случае автор берет любой остаток - какой заблагорассудится, чтобы пользователям учетной системы было не скучно
    т.е. теоретически дважды выполненный запрос вернет разные результаты на одних и тех же данных)
  • xmen (29.11.10 11:28) [16]

    > >xmen   (26.11.10 10:22) [11]>неаккуратно - поясните.нет
    > псевдонимов у таблиц и полей - это чревато непредсказуемым
    > результатом запроса

    что именно мне нужно ставить и где, чтобы такого не произошло?

    по поводу rownum: т.е. Вам всё равно какой из двух остатков с одним и тем же временем брать?)пора бы задуматься об уникальном идентификаторе записи или - как минимум - сменить тип поля на timestamp



    Мне не все равно, но другого варианта я не вижу. Скорее всего у записи есть уникальный идентификатор, но мне эта информация не доступна.
    Я не разработчки данной системы, но ведь ни кто мне запрещает мне использовать свои запросы ...


    > решение из [2] никак ? заменив MIN на MAXНасколько я вижу,
    >  у тебя остаток все время уменьшается в течение одной даты.
    >

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


    > Кщд   (29.11.10 08:51) [15]
    > >Inovet ©   (26.11.10 20:41) [13]>невыполнимо, нет уникального
    > признака, какая проводка была первой. >Где здесь наименьшее
    > время?абсолютно в точку)в этом случае автор берет любой
    > остаток - какой заблагорассудится, чтобы пользователям учетной
    > системы было не скучнот.е. теоретически дважды выполненный
    > запрос вернет разные результаты на одних и тех же данных)


    Все верно, я беру любую, но это не критично, суть в том, что такую работу нужно делать либо вручную, либо как-то ее автоматизировать, был выбран именно второй вариант, в итоге есть база на акссессе, которая через vba и ado цепляется к oracle, выполняет запрос, забирает данные, далее они другим запросом сравниваются с контрольными значениями, результаты отклонений анализируется сотрудником, берутся объяснения, наказываются люди - последняя часть стандартна :-)
  • Кщд (29.11.10 12:27) [17]
    >xmen   (29.11.10 11:28) [16]
    >что именно мне нужно ставить и где, чтобы такого не произошло?
    псевдонимы(alias) таблиц(обязательно) и полей(желательно).

    >Мне не все равно, но другого варианта я не вижу.
    Вы понимаете, что дважды выполнив Ваш запрос за 08.05.2010, Вы можете получить РАЗНЫЕ суммы остатка?

    >Все верно, я беру любую, но это не критично
    если для Вас это некритично, то можно просто воспользоваться ф-цией random для получения остатка на дату)
  • xmen (29.11.10 12:43) [18]

    > >xmen   (29.11.10 11:28) [16]>что именно мне нужно ставить
    > и где, чтобы такого не произошло?псевдонимы(alias) таблиц(обязательно)
    > и полей(желательно).

    ммм, пример можно?


    > >Мне не все равно, но другого варианта я не вижу. Вы понимаете,
    >  что дважды выполнив Ваш запрос за 08.05.2010, Вы можете
    > получить РАЗНЫЕ суммы остатка?

    вы понимаешь, что если у вас в кармане 10 000, а машина стоит 1 000 000, то будь у вас хоть 9 000, хоть 11 000, вы все равно не сможете ее купить.
    Там ситуация такова, что если нужное мне превышение будет, то оно будет на сотни тысяч и это все равно вылезет.
    Это как превышение скорости до 10 км/ч не является нарушением :-)
    Если вы знаете другой вариант решения, то выкладывайте, буду рад услышать, применить.


    > >Мне не все равно, но другого варианта я не вижу. Вы понимаете,
    >  что дважды выполнив Ваш запрос за 08.05.2010, Вы можете
    > получить РАЗНЫЕ суммы остатка?

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


    > >Все верно, я беру любую, но это не критичноесли для Вас
    > это некритично, то можно просто воспользоваться ф-цией random
    > для получения остатка на дату)

    я подумаю :-)
  • Кщд (29.11.10 14:37) [19]
    >xmen   (29.11.10 12:43) [18]
    >ммм, пример можно?
    google: sql table alias

    >Если вы знаете другой вариант решения, то выкладывайте, буду рад >услышать, применить.

    >Кщд   (29.11.10 08:46) [14]
    >пора бы задуматься об уникальном идентификаторе записи или - как >минимум - сменить тип поля на timestamp
    в конце концов, если добавить/сменить тип поля в исходной таблице нет возможности, повесить триггер, котором писать сумму остатка с уникальным идентификатором в свою таблицу

    >Понимаю, поэтому буду выполнять 1 раз
    и получать случайное значение из таблицы
    бессмысленная работа
 
Конференция "Базы" » Получение остатков на каждую дату
Есть новые Нет новых   [134431   +15][b:0][p:0.004]