for flooders
:: Главная :: Решения :: Статьи :: Сайт М. Дроздова :: Файловый архив :: Книга по VFP 9 :: Русский Help Online :: OFF-LINE Форум
   Л и с о в о д ы   в с е х   с т р а н,  о б ъ е д и н я й т е с ь !!!  

Список Форумов  :: Не фоксом единым
   :: Помощь сайту :: 

Таблица группы (вертикальная в горизонтальную)
VeterVFP
Автор

Сообщений: 347
Откуда: Москва
Дата: 11.05.18 16:37:36ОтветитьЦитировать
Приветствую.
Есть вертикальная таблица с номерами, объединенными в группы:
Группа, Номер  
  01    1.1  
  01    1.2  
  01    1.3  
  02    2.1  
  02    2.2
Как оптимально получить из нее горизонтальную цепочку для каждой группы (по принципу "каждый с каждым")?
Я так понимаю, что-то типа транспонирования, но мне ничего агрегатного не нужно, лишь цепочку.
Можно ли SQL-ем или придется таки цикл крутить по номерам?

Т.е. из Grps_Vert получить Grps_Horiz
CREATE CURSOR Grps_Vert (Gr C(2), Nomer C(3))  
  INSERT INTO Grps_Vert VALUES ('01', '1.1')  
  INSERT INTO Grps_Vert VALUES ('01', '1.2')  
  INSERT INTO Grps_Vert VALUES ('01', '1.3')  
  INSERT INTO Grps_Vert VALUES ('01', '1.4')  
  INSERT INTO Grps_Vert VALUES ('02', '2.1')  
  INSERT INTO Grps_Vert VALUES ('02', '2.2')  
  LOCATE  
  BROWSE LAST NOWAIT  
    
  CREATE CURSOR Grps_Horiz (Nomer1 C(3), Nomer2 C(3))  
  INSERT INTO Grps_Horiz VALUES ('1.1', '1.2')  
  INSERT INTO Grps_Horiz VALUES ('1.1', '1.3')  
  INSERT INTO Grps_Horiz VALUES ('1.1', '1.4')  
  INSERT INTO Grps_Horiz VALUES ('1.2', '1.3')  
  INSERT INTO Grps_Horiz VALUES ('1.2', '1.4')  
  INSERT INTO Grps_Horiz VALUES ('1.3', '1.4')  
    
  INSERT INTO Grps_Horiz VALUES ('2.1', '2.2')  
  LOCATE  
  BROWSE LAST NOWAIT
Ratings: 0 negative/0 positive

Re: Таблица группы (вертикальная в горизонтальную)
PaulWist

Сообщений: 12918
Дата: 11.05.18 17:52:42ОтветитьЦитировать
Транспорировать надо в фоксе?

Если в MSSQL, то Pivot.


------------------
Есть многое на свете, друг Горацио...
Что и не снилось нашим мудрецам.
(В.Шекспир Гамлет)
Ratings: 0 negative/0 positive

Re: Таблица группы (вертикальная в горизонтальную)
spinz

Сообщений: 5262
Дата: 11.05.18 18:11:58ОтветитьЦитировать
нифига не понял, но лефтджойн по полю группы разве не?


------------------
Позовите санитаров
Ratings: 0 negative/0 positive

Re: Таблица группы (вертикальная в горизонтальную)
Igor Korolyov

Сообщений: 31838
Дата: 11.05.18 18:48:32ОтветитьЦитировать
SELECT c1.Nomer Nomer1, c2.Nomer Nomer2 ;  
   FROM Grps_Vert c1 INNER JOIN Grps_Vert c2 ;  
    ON c1.Gr =c2.Gr AND c1.Nomer < c2.Nomer ;  
     ORDER BY c1.Nomer, c2.Nomer

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

К "транспонированию", т.е. "повороту", превращению записей в поля, а полей в записи это не имеет никакого отношения.

P.S. Это определённый вариант картезианского произведения ("уполовиненный" по сути), т.е. если в группе будет, скажем, 100 записей, то в итоговой выборке их станет уже около 5 тысяч


------------------
WBR, Igor




Исправлено: Igor Korolyov, 11.05.18 18:52
Ratings: 0 negative/0 positive

Re: Таблица группы (вертикальная в горизонтальную)
of63

Сообщений: 11498
Откуда: Н.Новгород
Дата: 11.05.18 20:10:22ОтветитьЦитировать
В формате SELECT-запорса опять не осилил...

В примере ТС, вероятно, полагается, что:
- для каждой группы (Gr) записей (группы никак не пересекаются друг с другом) надо получить
- все возможные комбинации пар значений (Nomer)

Т.к. группы не пересекаются, то можно все это изложить просто до попарного перебора. Схематично:
CREATE (m.b) (N1, N2)  && выходная таблица  
 * SET FILTER TO Gr=m.группа  && группы получены DISTINCT-снимком из исходной таблички. Переберем их в FOR EACH m.группа  
  SELECT (m.a)  && исходная таблица  
  SCAN  
     m.r = RECNO()  
     m.x = Nomer  
     SCAN FOR RECNO()>m.r  && перебираем записи НИЖЕ каждой текущей  
          INSERT INTO (m.b) VALUES (m.x, Nomer)    
     ENDSCAN  
     GO RECORD (m.r)  
  ENDSCAN  && исходная таблица  
Ratings: 1 negative/0 positive

Re: Таблица группы (вертикальная в горизонтальную)
VeterVFP
Автор

Сообщений: 347
Откуда: Москва
Дата: 14.05.18 12:47:11ОтветитьЦитировать
Пардон, по ошибке залепил тему не в тот раздел. Просьба в ФОКС перенести!.
Нужно все это в VFP9.
Игорь верно понял - похоже, получилось то, что надо! Спасибо!



Исправлено: VeterVFP, 14.05.18 12:47
Ratings: 0 negative/0 positive

Re: Таблица группы (вертикальная в горизонтальную)
VeterVFP
Автор

Сообщений: 347
Откуда: Москва
Дата: 21.05.18 13:19:17ОтветитьЦитировать
Появилось доп условие для отбора по наличию признака у номера.
Репро такой:
CREATE CURSOR Grps_Vert (Gr C(2), Prizn C(2), Nomer C(3))  
  INSERT INTO Grps_Vert VALUES ('01', 'AA', '1.1')  
  INSERT INTO Grps_Vert VALUES ('01', 'BB', '1.2')  
  INSERT INTO Grps_Vert VALUES ('01', 'AA', '1.3')  
  INSERT INTO Grps_Vert VALUES ('01', 'CC', '1.4')  
    
  INSERT INTO Grps_Vert VALUES ('02', 'AA', '2.1')  
  INSERT INTO Grps_Vert VALUES ('02', 'AA', '2.2')  
    
  INSERT INTO Grps_Vert VALUES ('03', 'AA', '3.2')  
  LOCATE  
  BROWSE LAST NOWAIT  
 ***  
    
  cPr= ''  
  cPr= 'AA'  
  IF EMPTY(cPr)  
     SELECT C1.Prizn P1, C1.Nomer Nomer1, C2.Prizn P2, C2.Nomer Nomer2;  
       FROM Grps_Vert C1;  
            INNER JOIN Grps_Vert C2 ON (C1.Gr=C2.Gr) AND (C1.Nomer < C2.Nomer);  
       ORDER BY C1.Nomer, C2.Nomer;  
       INTO CURSOR Result_Curs  
  ELSE  
     SELECT C1.Prizn P1, C1.Nomer Nomer1, C2.Prizn P2, C2.Nomer Nomer2;  
       FROM Grps_Vert C1;  
            INNER JOIN Grps_Vert C2 ON (C1.Gr=C2.Gr) AND (C1.Nomer <> C2.Nomer);  
       WHERE C1.Prizn= cPr;  
       ORDER BY C1.Nomer, C2.Nomer;  
       INTO CURSOR Result_Curs  
  ENDIF  
  LOCATE  
  BROWSE LAST NOWAIT
При наличии ограничивающего признака нужно также получить пары номеров, но уже только те, где этот признак = cPr.
Сделал условие отбора (в ветке ELSE) - список получается верный по сути, но с дублированием пар, где у обоих номеров признак одинаковый (только зеркально).
Т.е. из репро получается такие дубли:
  
  АА / 1.1 - АА / 1.3  
  АА / 1.3 - АА / 1.1  
  АА / 2.1 - АА / 2.2  
  АА / 2.2 - АА / 2.1
Как их убрать?


2 moderators: Перекиньте тему в раздел Фокса, плиз!
Ratings: 0 negative/0 positive

Re: Таблица группы (вертикальная в горизонтальную)
Igor Korolyov

Сообщений: 31838
Дата: 21.05.18 13:50:59ОтветитьЦитировать
Ну так ты ж сам написал во 2 запросе <> вместо < в первом... Так получается картезианское произведение за вычетом "диагонали" сам-с-собой соединённых.
Кроме того, где условие C2.Prizn = m.cPr ?
Я так понимаю надо ж "только из подходящих" пары составлять, а не "подходящие со всеми остальными"...
Кроме того, при штатной установке SET ANSI OFF второй запрос будет работать идентично первому, если в m.cPr будет пустая строка (сравнение до исчерпания более короткой строки - для "пустой" строки это значит что ограничения по сути нет вообще).
Кстати, именно по этой причине стоит при задании cPR для этого запроса всегда его явно дополнять до размера поля - а то пропишешь там "А" и он бодро возьмёт и "А" и "АА" и "АБ" из таблицы...


------------------
WBR, Igor
Ratings: 0 negative/0 positive

Re: Таблица группы (вертикальная в горизонтальную)
VeterVFP
Автор

Сообщений: 347
Откуда: Москва
Дата: 21.05.18 14:43:20ОтветитьЦитировать
Igor Korolyov
Кроме того, где условие C2.Prizn = m.cPr ?
Я так понимаю надо ж "только из подходящих" пары составлять, а не "подходящие со всеми остальными"...
Нет, как раз надо "подходящие со всеми остальными"! Поэтому и условие только по C1.Prizn.
Т.е. результат почти нужный, за исключением этих "зеркальных" дублей, которых может получиться много.
Вот и не пойму, как их убрать.

Igor Korolyov
при штатной установке SET ANSI OFF второй запрос будет работать идентично первому, если в m.cPr будет пустая строка (сравнение до исчерпания более короткой строки - для "пустой" строки это значит что ограничения по сути нет вообще).
Да, это в реальном коде я предусмотрел. Да и пустая по
IF EMPTY(cPr)
уже отсечется.
Ratings: 0 negative/0 positive

Re: Таблица группы (вертикальная в горизонтальную)
Igor Korolyov

Сообщений: 31838
Дата: 21.05.18 15:44:57ОтветитьЦитировать
VeterVFP
Igor Korolyov
Кроме того, где условие C2.Prizn = m.cPr ?
Я так понимаю надо ж "только из подходящих" пары составлять, а не "подходящие со всеми остальными"...
Нет, как раз надо "подходящие со всеми остальными"! Поэтому и условие только по C1.Prizn.
Не вижу логики. Если смотреть "без дублей", то пара должна быть НЕУПОРЯДОЧЕННОЙ - т.е. 1.1-1.2 и 1.2-1.1 по сути одно и то же. и тогда признак учитывать нужно "с обоих сторон". Если же признак учитывается лишь с одной стороны, то твой "результат" сразу некорректен. Где пара
АА/1.1 - BB/1.2
?
И тогда корректное условие должно иметь смысл "хотя бы с одной стороны есть АА" - но никак не "слева есть, справа нет".

Хотя в любом случае это неправильно... Если ЕСТЬ разница между "сторонами", то и результат должен быть "упорядоченным", и 1.1-1.2 и 1.2-1.1 автоматически становятся РАЗНЫМИ парами...

Ну да если "очень хочется", добавь условие OR C2.Prizn = m.cPr вместе с условием C1.Nomer < C2.Nomer. Да, некоторые пары будут "перевёрнуты", но какая разница, если это именно "просто пара", т.е. сочетание двух элементов одного и того-же смысла.
Если нужно именно "упорядоченное" (1.1-1.2 и 1.2-1.1 это совершенно разная штука) - другая задача получается. Наверное через UNION можно сделать.


VeterVFP
Да и пустая по
IF EMPTY(cPr)
уже отсечется.
Речь про то что задача решалась бы ОДНИМ универсальным запросом, безо всяких IF.


------------------
WBR, Igor
Ratings: 0 negative/0 positive

Re: Таблица группы (вертикальная в горизонтальную)
VeterVFP
Автор

Сообщений: 347
Откуда: Москва
Дата: 21.05.18 16:33:11ОтветитьЦитировать
Igor Korolyov
Если смотреть "без дублей", то пара должна быть НЕУПОРЯДОЧЕННОЙ - т.е. 1.1-1.2 и 1.2-1.1 по сути одно и то же. и тогда признак учитывать нужно "с обоих сторон"
Игорь, именно так и надо, т.е. "справа" или "слева" пара - неважно: АА/1.1 - АА/1.2 будет равносильна АА/1.2 - АА/1.1 и именно поэтому и считаются они дублями, которые мне и нужно убрать. Т.е. можно оставить любой вариант из них - сторона "лево" или "право" не важно.
Конечно удобнее было бы с одной стороны иметь все записи по этому признаку, но ПОКА это не существенно.

Igor Korolyov
Если же признак учитывается лишь с одной стороны, то твой "результат" сразу некорректен. Где пара
АА/1.1 - BB/1.2
Хм. Не понял, в репро в результатном курсоре вижу эту пару.

Igor Korolyov
добавь условие OR C2.Prizn = m.cPr вместе с условием C1.Nomer < C2.Nomer.
Ты про такой вариант?
  
  SELECT C1.Prizn P1, C1.Nomer Nomer1, C2.Prizn P2, C2.Nomer Nomer2;  
    FROM Grps_Vert C1;  
         INNER JOIN Grps_Vert C2 ON (C1.Gr=C2.Gr) AND (C1.Nomer <> C2.Nomer) AND;  
               (C1.Nomer < C2.Nomer OR C2.Prizn=cPr);  
    WHERE C1.Prizn=cPr;  
    ORDER BY C1.Nomer, C2.Nomer;  
    INTO CURSOR Result_Curs
Но в этом примере у меня выпадает пара АА/1.3 - ВВ/1.2
Или я не понял твою мысль?
Ratings: 0 negative/0 positive

Re: Таблица группы (вертикальная в горизонтальную)
Igor Korolyov

Сообщений: 31838
Дата: 21.05.18 18:38:03ОтветитьЦитировать
VeterVFP
в репро в результатном курсоре вижу эту пару.
В тексте ты её не указал - вот я и в затруднении - нужна она или уже нет

VeterVFP
Ты про такой вариант?
Нет, не так.
SELECT C1.Prizn P1, C1.Nomer Nomer1, C2.Prizn P2, C2.Nomer Nomer2 ;  
   FROM Grps_Vert C1 ;  
   INNER JOIN Grps_Vert C2 ON C1.Gr=C2.Gr AND C1.Nomer < C2.Nomer ;  
   WHERE C1.Prizn = m.cPr OR C2.Prizn = m.cPr ;  
   ORDER BY C1.Nomer, C2.Nomer ;  
   INTO CURSOR Result_Curs
Если всё в ON писать, то будет
SELECT C1.Prizn P1, C1.Nomer Nomer1, C2.Prizn P2, C2.Nomer Nomer2 ;  
   FROM Grps_Vert C1 ;  
   INNER JOIN Grps_Vert C2 ON C1.Gr=C2.Gr AND C1.Nomer < C2.Nomer AND ;  
    (C1.Prizn = m.cPr OR C2.Prizn = m.cPr) ;  
   ORDER BY C1.Nomer, C2.Nomer ;  
   INTO CURSOR Result_Curs

Разница между запросом с cPr="AA" и cPr="" лишь в записи BB/1.2-CC/1.4, где ни с одной ни с другой стороны нет нужного АА.
И да, этот запрос ОДИН работает и для заданного и для не заданного (пустого) cPr - лишь бы настройка SET ANSI была в OFF (как оно и есть по умолчанию).
Никаких IF не требуется.


------------------
WBR, Igor
Ratings: 0 negative/0 positive

Re: Таблица группы (вертикальная в горизонтальную)
VeterVFP
Автор

Сообщений: 347
Откуда: Москва
Дата: 22.05.18 11:48:01ОтветитьЦитировать
Игорь, вроде уловил - переделал на 1 запрос. Пока не вижу нестыковок в результатах
Спасибо!
Единственное, что, т.к. это все на свободных ДБФах построено, то при больших выборках начинает зависать прога (а там полу-картезианское может достигать 10ки млн ).
И даже когда я делал сохранение в CSV
COPY TO (cFileSave) CSV AS 866
тоже зависало периодически. Это из-за "тяжелых" объемов?


Исправлено: VeterVFP, 22.05.18 13:39
Ratings: 0 negative/0 positive

Re: Таблица группы (вертикальная в горизонтальную)
Igor Korolyov

Сообщений: 31838
Дата: 22.05.18 13:07:40ОтветитьЦитировать
10М это прилично. Особенно если без оптимизации - т.е. если по ходу дела фокс генерит 100М и без индексов отбрасывает "ненужные" записи - скажем те что "между группами" образуются. А просто выброска dbf в csv (независимо от того free таблица или нет, досовская она или виндовая) - не должна тормозить. Тут если что и мешает, то это вне фокса (АВ, слабая сеть, дохлый жёсткий диск).


------------------
WBR, Igor
Ratings: 0 negative/0 positive



Извините, только зарегистрированные пользователи могут писать в этом форуме.

On-line: 51 and Guests: 51


© 2000-2018 Fox Club 
Яндекс.Метрика