Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Web программирование > SQL, базы данных
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 28.07.2010, 19:21   #1
Rekky
Форумчанин
 
Аватар для Rekky
 
Регистрация: 14.01.2009
Сообщений: 312
По умолчанию Добавление записи в запросе при условии

Доброго дня всем.
Даны два столбца (выбираются запросом). В первом даты по возрастанию. второй характеризует високосность года.
1 28.07.2010 365
2 30.09.2010 365
3 30.12.2010 365
4 30.03.2011 365
5 30.06.2011 365
6 30.09.2011 365
7 30.12.2011 365
8 30.03.2012 366
9 02.07.2012 366
10 01.10.2012 366
11 31.12.2012 366
12 01.04.2013 365
13 01.07.2013 365

Необходимо при смене года с обычного на високосный и наоборот добавлять запись: 31.12.<нужный год> <кол-во дней в году>, так же в запросе.
например между 7 и 8 записью должна появится 31.12.2011 365
Буду признательна за помощь.
Никому не поставить нас на колени! Мы лежали и будем лежать!
Rekky вне форума Ответить с цитированием
Старый 28.07.2010, 21:28   #2
soleil@mmc
SQL-коддинг
Участник клуба
 
Регистрация: 16.01.2009
Сообщений: 1,192
По умолчанию

субд?
а что делать в вашем случае для записи №11 - она на месте, но по условию
Цитата:
при смене года с обычного на високосный и наоборот добавлять запись: 31.12.<нужный год> <кол-во дней в году>
soleil@mmc вне форума Ответить с цитированием
Старый 29.07.2010, 09:15   #3
Rekky
Форумчанин
 
Аватар для Rekky
 
Регистрация: 14.01.2009
Сообщений: 312
По умолчанию

извините, забыла указать.oracle.
между 11 и 12 строк добавлять не нужно.
Никому не поставить нас на колени! Мы лежали и будем лежать!
Rekky вне форума Ответить с цитированием
Старый 29.07.2010, 09:51   #4
Serge_Bliznykov
Старожил
 
Регистрация: 09.01.2008
Сообщений: 26,229
По умолчанию

к слову, это обязательно надо в SQL запросе сделать?
а процедура на PL/SQL не пойдёт?
или, можно это вообще на клиенте сделать... (если он есть, конечно )
Serge_Bliznykov вне форума Ответить с цитированием
Старый 29.07.2010, 10:10   #5
Rekky
Форумчанин
 
Аватар для Rekky
 
Регистрация: 14.01.2009
Сообщений: 312
По умолчанию

обязательно в запросе.
есть предположение сделать все юнионами.
например к выборке всех дат добавить сначала юнион где есть переход с 365 на 366. там где все 365 заменить дату на 31.12, затем добавить юнион с 366 на 365 и изменить значение. затем отсортировать все это дело по дате.
но как в where сравнить две соседние даты большой для меня вопрос)
Код:
 where (year_long = 365 and lead(year_long) over(partition by id1 order by dateout) = 366)
ругается, что функции окна в данном месте запрещены((
Здесь я пыталась использовать union all

Также есть идея с использованием union. К выборке всех дат добавить юнион и там уже в селекте проверять даты где есть переход и заменять case? дублирующиеся строки уберутся union- ом. Но это пока в теории, возможно встретится еще какое препятствие. к тому же это очень громоздко.
Никому не поставить нас на колени! Мы лежали и будем лежать!

Последний раз редактировалось Rekky; 29.07.2010 в 10:16.
Rekky вне форума Ответить с цитированием
Старый 29.07.2010, 11:17   #6
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

Цитата:
как в where сравнить две соседние даты большой для меня вопрос)
Есть в Оракле так называемые Аналитические функции
Цитата:
Функции LEAD и LAG можно рассматривать как способы индексации в пределах
группы. С помощью этих функций можно обратиться к любой отдельной строке.
Может тебе они помогут?
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 29.07.2010, 11:29   #7
Rekky
Форумчанин
 
Аватар для Rekky
 
Регистрация: 14.01.2009
Сообщений: 312
По умолчанию

Так вот lead в where использовать нельзя..ну я решила воспользоваться вторым способом, где использовать в селект можно.
Код:
select id1, date, year_long from table
union id1,
select 
case when year_long = 365 and lead(year_long) over(partition by id1 order by date) = 366 and to_char(date) <> '31.12.'||To_char(date, 'yyyy')
then to_date('31.12.'||to_char(date,'yyyy'),'dd.mm.yyyy')
when year_long = 366 and lead(year_long) over(partition by id1 order by date) = 365 and to_char(date) <> '31.12.'||To_char(date, 'yyyy')
then to_date('31.12.'||to_char(date,'yyyy'),'dd.mm.yyyy')
else date
end date,
id1
order by id, dateout
Дублирующие строки убирает, но и все вроде бы правильно работает на примере...но не знаю насколько это безопасно и корректно
Никому не поставить нас на колени! Мы лежали и будем лежать!
Rekky вне форума Ответить с цитированием
Старый 29.07.2010, 11:52   #8
soleil@mmc
SQL-коддинг
Участник клуба
 
Регистрация: 16.01.2009
Сообщений: 1,192
По умолчанию

чота даже обкатать идеи не на чем в данный момент

идея №1
добавляем поле
Код:
nvl(lag(year_long) over(order by dateout), year_long)
(чота не очевидно для чего вам там партишн по айди, в условии никаких айди нет, но при необходимости прикрутите и партишн)
потом сверху на это поле прикручиваем кейс, в котором ищем переход 366 -> 365 и 365 -> 366
полкчаем такое (с учетом проверки на существование такой даты в наборе данных - внутренний кейс)
Код:
case
when
  ((nvl(lag(year_long) over(order by dateout), year_long) = 366) and (year_long = 365) 
or (nvl(lag(year_long) over(order by dateout), year_long) = 365) and (year_long = 366))
then 
     case 
     when (dateout <> (trunc(dateout, 'yy') + year_long - 1))  then 1
     else 0
     end
  else 0
end
в итоге получаем нечто такое
Код:
select
  dateout,
  year_long
from t
union all
select
  trunc(dateout, 'yy') + year_long -1 dateout,
  year_long
from(
select
  dateout,
  year_long,
  case
   when
      ((nvl(lag(year_long) over(order by dateout), year_long) = 366) and (year_long = 365) 
      or (nvl(lag(year_long) over(order by dateout), year_long) = 365) and (year_long =  366))
    then 
       case 
        when (dateout <> (trunc(dateout, 'yy') + year_long - 1))  then 1
        else 0
        end
      else 0
    end f1
from t)
where 0=0
   and f1 = 1

идея №2
раз все знают правила определения високосного года
Цитата:
год является високосным, если он кратен 4 и при этом не кратен 100, либо кратен 400. Год не является високосным, если он не кратен 4, либо кратен 100 и не кратен 400.
по этим правилам определить какой год високосный из данного набора записей, есть ли у него предшествующий год в этом наборе и по этим данным добавить недостающие строки


апд
еще раз пеерчитал свою писанину и понял что lag() везде меняем на lead() и все будет работать

2 Rekky

неявное приведение даты в строку может оказаться бомбой замедленного действия
Цитата:
to_char(date) <> '31.12.'||To_char(date, 'yyyy')
апд 2
проверил пример после замены лаг на лид - все работает как надо
Код:
with 
  t as (
  select to_date('28.07.2010', 'DD.MM.YYYY') dateout, 365 year_long from dual union all
  select to_date('30.09.2010', 'DD.MM.YYYY'), 365 from dual union all
  select to_date('30.12.2010', 'DD.MM.YYYY'), 365 from dual union all
  select to_date('30.03.2011', 'DD.MM.YYYY'), 365 from dual union all
  select to_date('30.06.2011', 'DD.MM.YYYY'), 365 from dual union all
  select to_date('30.09.2011', 'DD.MM.YYYY'), 365 from dual union all
  select to_date('30.12.2011', 'DD.MM.YYYY'), 365 from dual union all
  select to_date('30.03.2012', 'DD.MM.YYYY'), 366 from dual union all
  select to_date('02.07.2012', 'DD.MM.YYYY'), 366 from dual union all
  select to_date('01.10.2012', 'DD.MM.YYYY'), 366 from dual union all
  select to_date('31.12.2012', 'DD.MM.YYYY'), 366 from dual union all
  select to_date('01.04.2013', 'DD.MM.YYYY'), 365 from dual union all
  select to_date('01.07.2013', 'DD.MM.YYYY'), 365 from dual
  )
  
select
  dateout,
  year_long
from t
union all
select
  trunc(dateout, 'yy') + year_long -1 dateout,
  year_long
from(
select
  dateout,
  year_long,
  case
   when
      ((nvl(lead(year_long) over(order by dateout), year_long) = 366) and (year_long = 365) 
      or (nvl(lead(year_long) over(order by dateout), year_long) = 365) and (year_long =  366))
    then 
       case 
        when (dateout <> (trunc(dateout, 'yy') + year_long - 1))  then 1
        else 0
        end
      else 0
    end f1
from t)
where 0=0
   and f1 = 1
order by dateout

Последний раз редактировалось soleil@mmc; 29.07.2010 в 12:36.
soleil@mmc вне форума Ответить с цитированием
Старый 29.07.2010, 13:03   #9
Rekky
Форумчанин
 
Аватар для Rekky
 
Регистрация: 14.01.2009
Сообщений: 312
По умолчанию

Да проверила по таблицам, все отлично работает, спасибо, ваш вариант пожалуй лучше только вопрос для чего нужно условие 0 = 0 ?
P.S. пыталась добавить вам отзыв, но не позволили придется ограничится СПАСИБО
Никому не поставить нас на колени! Мы лежали и будем лежать!
Rekky вне форума Ответить с цитированием
Старый 29.07.2010, 13:39   #10
soleil@mmc
SQL-коддинг
Участник клуба
 
Регистрация: 16.01.2009
Сообщений: 1,192
По умолчанию

Цитата:
Сообщение от Rekky Посмотреть сообщение
только вопрос для чего нужно условие 0 = 0 ?
для красоты
и еще для легкого комментирования остальных фильтров запроса
soleil@mmc вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Вывод ошибки при условии.... Arinka Помощь студентам 8 05.06.2010 14:54
Добавление записи в реестр при открытии книги ru3000 Microsoft Office Excel 3 29.07.2009 04:49
Добавление записи через список в связанную таблицу(при связи с Access) megaten БД в Delphi 5 17.05.2009 15:57
Разметка страницы при условии axaptaalex Microsoft Office Excel 2 20.03.2009 18:36
DBGridEh+EditMask при условии. Jenya БД в Delphi 1 03.03.2008 13:58