:: Visual Foxpro, Foxpro for DOS
Как сформулировать запрос для Cursor Adapter-a
spammail_88
Автор

Сообщений: 108
Дата регистрации: 13.11.2010
Хочу создать Cursor Adapter с 2-ух таблиц. Первая с данными по людях, которые нужно будет менять, 2-ая – справочник с фамилиями (данные туда выгружаться не будут, колонка с фамилией нужна просто для визуального удобства пользователя). Проблема в том, что в справочнике фамилий люди могут повторятся, то есть несколько записей с одним и тем же идентификационным номером.
Как сформулировать запрос в SelectCMD, чтобы в результате не дублировались строки из основной таблицы (по аналогии с SET RELATION TO – подтягивало фамилию из первой-лучшей записи справочника)

На примере:

Таблица данных:
Id Data
1 10
1 11
2 43

Таблица Справочник:
Id Fam
1 А
2 Б
2 Б

Запрос:
SELECT TFam.Fam,TData.* FROM TData LEFT OUTER JOIN TFam ON TData.ID==TFam.ID

Я получаю:
Fam Id Data
А 1 10
А 1 11
Б 2 43
Б 2 43

А надо:
Fam Id Data
А 1 10
А 1 11
Б 2 43



Исправлено 1 раз(а). Последнее : spammail_88, 06.11.18 19:31
Ratings: 0 negative/0 positive
Re: Как сформулировать запрос для Cursor Adapter-a
of63

Сообщений: 25254
Откуда: Н.Новгород
Дата регистрации: 13.02.2008
> Проблема в том, что в справочнике фамилий люди могут повторятся, то есть несколько записей с одним и тем же идентификационным номером.

Или с разными ИН (идент. именами) одинаковые фамилии?
Просто, если "справочник", то там обычно ИН все разные, на то он и ИН. Или справочник другой, особенный?
Ratings: 0 negative/0 positive
Re: Как сформулировать запрос для Cursor Adapter-a
spammail_88
Автор

Сообщений: 108
Дата регистрации: 13.11.2010
of63
Или справочник другой, особенный?
Cправочник другой, особенный. ИН - не ключ. Один человек может иметь несколько позиций.

of63
Или с разными ИН (идент. именами) одинаковые фамилии?
В 99% случаев одинаковые ИН и Фамилии. Но бывают редкие исключения: вышла замуж, опечатка в фамилии. Тогда одинаковые ИН, а фамилии разные – нужно взять любую, разберутся.



Исправлено 1 раз(а). Последнее : spammail_88, 06.11.18 19:47
Ratings: 0 negative/0 positive
Re: Как сформулировать запрос для Cursor Adapter-a
of63

Сообщений: 25254
Откуда: Н.Новгород
Дата регистрации: 13.02.2008
Давай попробуем такую структуру справочника предположить:
ID, тип I - уникальный номер записи справочника
ИН, C(11) - например ИНН (известный, или пусто, или, неправильно введенный, бывает, что совпадает с другими записями справочника)
ФАМ C(40) - фамилия (известная на сегодня, может женщина его уже поменяла, может перепутаны буквы е-ё, л-лл...)
ФАМр, (C(40) - фамилия при рождении (м.б. те же ошибки ввода и интерпретации)
ИМЯ, C(40)
ОТЧ, C(40)

Похожа структура?
Если нет - приведи свою (с комментами, примером)

Если да, то что означает вопрос:
>чтобы в результате не дублировались строки из основной таблицы (по аналогии с SET RELATION TO – подтягивало фамилию из первой-лучшей записи справочника)

Не дублировались по какому полю?
Ratings: 0 negative/0 positive
Re: Как сформулировать запрос для Cursor Adapter-a
AndyNigmatec

Сообщений: 1573
Откуда: Волгоград
Дата регистрации: 28.06.2015
А при чем здесь вообще курсорадаптер то ... вам надо запрос сначала отработать и причесать чтобы получалось именно то что вам нужно, а уж как и где вы его потом будете использовать дело второе )))

spammail_88
TData.ID==TFam.ID
- у вас поле ID символьно типа что ли?
и еще лучше в запросе таки явно перечислить все выбираемые поля (а не * писать) - иначе потом можете некоторой неразберихи поиметь



Исправлено 1 раз(а). Последнее : AndyNigmatec, 06.11.18 20:10
Ratings: 0 negative/0 positive
Re: Как сформулировать запрос для Cursor Adapter-a
of63

Сообщений: 25254
Откуда: Н.Новгород
Дата регистрации: 13.02.2008
> SELECT TFam.Fam,TData.* FROM TData LEFT OUTER JOIN TFam ON TData.ID==TFam.ID

поле ID - это числа, тогда == не нужен
TData (пример - 1,10),
TFam (пример - 1,фамилия)
хотим извлечь: фамилия, ID, число
не устраивает: "чтобы в результате не дублировались строки из основной таблицы" (основная - это TData вероятно?)
""
Я получаю:
Fam Id Data
А 1 10
А 1 11Б 2 43
Б 2 43
Б 2 43 лишняя

А надо:
Fam Id Data
А 1 10
А 1 11
Б 2 43

> SELECT TFam.Fam,TData.* FROM TData LEFT OUTER JOIN TFam ON TData.ID=TFam.ID
ну, добавь DISTINCT в SELECT набор_полей DISTINCT
или группировку GROUP BY TFam.Fam, TData.Id (если SET ENGINEBEHAVIOR 70)
Ratings: 0 negative/0 positive
Re: Как сформулировать запрос для Cursor Adapter-a
spammail_88
Автор

Сообщений: 108
Дата регистрации: 13.11.2010
of63
Давай попробуем такую структуру справочника предположить:
Структура справочника:
FKey: C(6) : уникальное поле справочника (учитывает должность, подразделение, один человек может быть привязан к разным подразделениям)
ID: С(11): ИН, для нерезидентов могут быть буквы (уникально определяет человека), для всех строк по одному человеку всегда одинаковое
FAM: С(40): фамилия, имя, отчество (могут быть ошибки, не всегда отвечает ИН)

Структура таблицы с данными, к примеру «Делами»
ID: С(11): ИН человека, который ведет дело (не зависит от должности, подразделения)
kDel: N(3): № дела (уникален для человека, но не для организации)
Data: C(254): Другие данные по делу



Исправлено 1 раз(а). Последнее : spammail_88, 06.11.18 21:05
Ratings: 0 negative/0 positive
Re: Как сформулировать запрос для Cursor Adapter-a
spammail_88
Автор

Сообщений: 108
Дата регистрации: 13.11.2010
of63
ну, добавь DISTINCT в SELECT набор_полей DISTINCT
Если я правильно понимаю, DISTINCT работает только для строки целиком. Нельзя сделать DISTINCT по какому-то полю. Только так?
SELECT DISTINCT TFam.Fam,TData.* FROM TData LEFT OUTER JOIN TFam ON TData.ID==TFam.ID
Если опечатка в фамилии, или в справочнике человек в одном подразделении числится по новой фамилии, а в другом по девичьей, все равно будет дубляж. (Б 2 43 лишняя )

of63
или группировку GROUP BY TFam.Fam, TData.Id (если SET ENGINEBEHAVIOR 70)
SET ENGINEBEHAVIOR 90
Ratings: 0 negative/0 positive
Re: Как сформулировать запрос для Cursor Adapter-a
of63

Сообщений: 25254
Откуда: Н.Новгород
Дата регистрации: 13.02.2008
> Если опечатка в фамилии
То тут другие "технологии", просто RELATION не подойдет

> SET ENGINEBEHAVIOR 90
Почему бы не SET ENGINEBEHAVIOR 70, для начала, зачем сразу жестко? )
когда "по аналогии с SET RELATION TO – подтягивало фамилию из первой-лучшей записи справочника"



Исправлено 1 раз(а). Последнее : of63, 06.11.18 21:15
Ratings: 0 negative/0 positive
Re: Как сформулировать запрос для Cursor Adapter-a
spammail_88
Автор

Сообщений: 108
Дата регистрации: 13.11.2010
of63
То тут другие "технологии"
Забили на нормализацию, где-то выиграли, а здесь проиграли. Ситуация с ошибками очень редкая, но бывает, когда клиент добавляет новую строчку по существующему сотруднику в справочник, фамилия сносится на автомате, по этому в 99% случаев – все хорошо. Но иногда клиент делает «ручные» правки – в результате возможны расхождения

of63
просто RELATION не подойдет
Подойдет. Мне не важно какая фамилия, с опечаткой, или без – это не критическая, дополнительная информацыя

of63
Почему бы не SET ENGINEBEHAVIOR 70
Другой уже код написан с учетом 90, не могу менять
Ratings: 0 negative/0 positive
Re: Как сформулировать запрос для Cursor Adapter-a
of63

Сообщений: 25254
Откуда: Н.Новгород
Дата регистрации: 13.02.2008
spammail_88
of63
То тут другие "технологии"
Забили на нормализацию, где-то выиграли, а здесь проиграли. Ситуация с ошибками очень редкая, но бывает, когда клиент добавляет новую строчку по существующему сотруднику в справочник, фамилия сносится на автомате, по этому в 99% случаев – все хорошо. Но иногда клиент делает «ручные» правки – в результате возможны расхождения

Не понимаю. "Редко" - это для нашего государства - факт "недостоверности", за это .бут деньгами, боьшими, если у вас пофамильный учет. Если это учет в ПОДФТ, тогда м.б. и нас..вать, понятно... Ручные правки хотят все, и исправит фамилию, неправильно введенную ранее, или бабы, сменившей фамилию. Для этого делается табличка истории фамилий (или она включена в табличку фамилий с статусом прошала, дата, например... И потом, при поиске чела, лазишь и в эту табличку тоже... Мудатория, согласен.


of63
просто RELATION не подойдет
Подойдет. Мне не важно какая фамилия, с опечаткой, или без – это не критическая, дополнительная информацыя

Это для нашего алгоритма "задвоения" фамилий и не важно, может. НО, тебе не нравятся "одинаковые" фамилии... Нигматулин и Нигматуллин - одинаковые фамилии ?


of63
Почему бы не SET ENGINEBEHAVIOR 70
Другой уже код написан с учетом 90, не могу менять

В фоксе его можно менять, и возвращать в предыдущее состояние
x = SET("ENGINEBEHAVIOR")
SET ENGINEBEHAVIOR 70
...код
SET ENGINEBEHAVIOR &x
Ratings: 0 negative/0 positive
Re: Как сформулировать запрос для Cursor Adapter-a
AndyNigmatec

Сообщений: 1573
Откуда: Волгоград
Дата регистрации: 28.06.2015
ммм ... а какую уникальность вы хотели получить ежели у вас сам справочник не уникален?

spammail_88
Таблица Справочник:
Id Fam
1 А
2 Б
2 Б

если же это очепятка и ID в справочнике уникальны, то ваш запрос должен быть (с небольшими поправками) вполне корректен (ну про * бог с ними ежели лень писать явно поля )

SELECT TFam.ID, TFam.Fam, TData.* FROM TData LEFT JOIN TFam ON TData.ID==TFam.ID ORDER BY TFam.ID

в результате вы получите по кажному человеку (ID) стока записей скока "дел" существует на этот ID в таблице TData, и даже еще довеском получите null-значения ID и Fam ежели какого-то ID не окажется в справочнике TFam, и не получите в выборку ID для которого нету связки с TData

ЗЫ а с SET ENGINEBEHAVIOR не вижу смысла играться - достаточно корректно sql-запрос написать, этот set нужен бывает только когда сильно в лом что-то древнее переписывать



Исправлено 7 раз(а). Последнее : AndyNigmatec, 06.11.18 21:50
Ratings: 0 negative/0 positive
Re: Как сформулировать запрос для Cursor Adapter-a
AndyNigmatec

Сообщений: 1573
Откуда: Волгоград
Дата регистрации: 28.06.2015
spammail_88
of63
или группировку GROUP BY TFam.Fam, TData.Id (если SET ENGINEBEHAVIOR 70)

ващета группировке SET ENGINEBEHAVIOR 70 не нужен )))

GROUP BY 1, 3 и т.д.



Исправлено 1 раз(а). Последнее : AndyNigmatec, 06.11.18 21:46
Ratings: 0 negative/0 positive
Re: Как сформулировать запрос для Cursor Adapter-a
of63

Сообщений: 25254
Откуда: Н.Новгород
Дата регистрации: 13.02.2008
Без 70 ругаться будет, возможно, что есть неоднозначный набор выходных данных. ругань фокса - типа неверный "гроуп бай", невнятный такой, но ругается.. Ну, может, я чего недосек, я не пробовал код, просто попистел )
Ratings: 0 negative/0 positive
Re: Как сформулировать запрос для Cursor Adapter-a
spammail_88
Автор

Сообщений: 108
Дата регистрации: 13.11.2010
AndyNigmatec
а какую уникальность вы хотели получить ежели у вас сам справочник не уникален?
Справочник уникален, но не по ID.
spammail_88
Структура справочника:
FKey: C(6) : уникальное поле справочника (учитывает должность, подразделение, один человек может быть привязан к разным подразделениям)
ID: С(11): ИН, для нерезидентов могут быть буквы (уникально определяет человека), для всех строк по одному человеку всегда одинаковое
FAM: С(40): фамилия, имя, отчество (могут быть ошибки, не всегда отвечает ИН)

of63
Без 70 ругаться будет
Так оно и есть.

of63
В фоксе его можно менять, и возвращать в предыдущее состояние
Как я уже писал - это CursorAdapter, который все время открыт. Я не могу на CursorFill скинуть в 70, а потом вернуть в 90. Там регулярно выполняются CursorRefresh.

Подумываю над тем, чтобы вообше в начале всей программы влепить SET ENGINEBEHAVIOR 70
В запросах я DISTINCT, UNION, GROUP BY(кроме вышеуказанного случая), HAVING, LIKE, TOP, ORDER BY не использую. Collate стоит Machine.
Чем я рискую?
Что могу потерять?
Rushmore будет работать как раньше?
Ratings: 0 negative/0 positive
Re: Как сформулировать запрос для Cursor Adapter-a
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
SELECT TUniqueFam.Fam, TData.* FROM TData LEFT OUTER JOIN (SELECT TFam.ID, MAX(TFam.Fam) Fam FROM TFam GROUP BY TFam.ID) TUniqueFam ON TData.ID==TUniqueFam.ID
Если полей из "справочника" надо >1 выбирать, то надо ещё сложнее огород городить (в идеале - завязываться на имеющийся уникальный набор полей - ну типа MAX(real_unique_id), и потом уже по нему одну запись и брать), т.к. просто MAX может из разных исходных записей "насобирать" итоговую запись. Конечно можно и MIN использовать - раз не суть важно какую из "одинаковых" записей брать. Чего-либо типа FIRST/LAST в фоксе нет, увы.


------------------
WBR, Igor
Ratings: 0 negative/1 positive
Re: Как сформулировать запрос для Cursor Adapter-a
of63

Сообщений: 25254
Откуда: Н.Новгород
Дата регистрации: 13.02.2008
Подумываю над тем, чтобы вообше в начале всей программы влепить SET ENGINEBEHAVIOR 70
В запросах я DISTINCT, UNION, GROUP BY(кроме вышеуказанного случая), HAVING, LIKE, TOP, ORDER BY не использую. Collate стоит Machine.

SET ENGINEBEHAVIOR 70 - просто упрощает контроль за вот такими словами типа "вернуть первую попавшуюся под условия запись"


Чем я рискую? Что могу потерять?
Не особо чем. Если прога была заточена под SET ENGINEBEHAVIOR 90, то значит там програмер писал под жесткие условия. Умягчение условий не ухудшит.


Rushmore будет работать как раньше?
Будет
Ratings: 0 negative/0 positive
Re: Как сформулировать запрос для Cursor Adapter-a
spammail_88
Автор

Сообщений: 108
Дата регистрации: 13.11.2010
Igor Korolyov
SELECT TUniqueFam.Fam, TData.* FROM TData LEFT OUTER JOIN (SELECT TFam.ID, MAX(TFam.Fam) Fam FROM TFam GROUP BY TFam.ID) TUniqueFam ON TData.ID==TUniqueFam.ID
Если справочник большой (может даже больше рабочей таблицы), как это все по сети работать будет?

В случае простенького запроса:
SELECT TFam.Fam,TData.* FROM TData LEFT OUTER JOIN TFam ON TData.ID==TFam.ID
Я делаю индекс по TFam.ID, и у меня все летает. По сети тягаю только маленькую (нужную) часть справочника. В Вашем случае, наверное, весь справочник полетит и никакие индексы не помогут. Правильно?
Ratings: 0 negative/0 positive
Re: Как сформулировать запрос для Cursor Adapter-a
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
spammail_88
Если справочник большой (может даже больше рабочей таблицы), как это все по сети работать будет?
Без указания дополнительных условий отбора - плохо. Собственно говоря, как и любой другой вариант запроса
spammail_88
В случае простенького запроса:
SELECT TFam.Fam,TData.* FROM TData LEFT OUTER JOIN TFam ON TData.ID==TFam.ID
Я делаю индекс по TFam.ID, и у меня все летает.
Толк от индекса будет лишь в том случае, если в "рабочей" таблице используется лишь 10-20-30% "кодов" имеющихся в "справочнике". Иначе - по сути целиком обе таблицы и будут выниматься, да ещё и в неоптимальном виде "через поиск по индексу". И, конечно же, очень большой толк будет если там ЕЩЁ какие-то условия имеются, сильно ограничивающие выборку из того-же TData.
spammail_88
По сети тягаю только маленькую (нужную) часть справочника.
Ну если запрос имеет дополнительные условия сильно сужающие "нужную" часть справоника, то да - может оказаться предпочтительным сначала соединение сделать, а потом уже группировку (в чистом виде DISTINCT не подойдёт, т.к. сам говоришь что ФИО могут "чуть чуть отличаться"). Опять же, это зависит от среднего количества "неуникальных" элементов в справочнике - одно дело если там одинаковый TFam.ID ну 2-3 изредка 4 раза будет встречаться, и совсем другое если там на каждый ID по 100500 записей.
spammail_88
В Вашем случае, наверное, весь справочник полетит и никакие индексы не помогут. Правильно?
В фоксе - да.
Вообще может оказаться предпочтительным просто сделать "материализованное представление" - т.е. выбрать то что в подзапросе в отдельную табличку, уже с уникальным TFam.ID - и использовать как "правильный" справочник. Конечно, если "изменчивость" TFam позволяет такое (не нужны данные всего минуту назад туда введенные/изменённые). Если можно позволить, скажем, раз в день эту табличку "обновлять" перезаполняя из большой.

Короче, не видя целиком всей картины нельзя однозначно что-то посоветовать. Нужно понимать какие ещё условия на этот запрос накладываются, и каково распределение данных по таблицам (общее число записей, сколько в среднем при "типичных" значениях параметров вынимается из TData (хотя бы в % отношении), сколько в среднем записей на один Id в TFam будет, каков размер записи в TFam)...


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: Как сформулировать запрос для Cursor Adapter-a
spammail_88
Автор

Сообщений: 108
Дата регистрации: 13.11.2010
О, вроде разобрался. Спасибо, Igor Korolyov, за Ваше MAX() с ним работает и при ENGINEBEHAVIOUR 90:
SELECT MAX(TFam.Fam),TData.* FROM TData LEFT OUTER JOIN TFam ON TData.ID==TFam.ID GROUP BY TData.ID,TData.kDel,TData.Data WHERE ...
И индексы работают, и запрос быстро выполняется.

Но возникло еще 2 вопроса:
1. Как это оформить в CursorAdapter-е? Вышеуказанный запрос пишу в SelectCMD. В UpdateNameList что писать: Fam TFam.Fam, или все же Fam MAX(TFam.Fam)? В любом случае при выполнении CursorFill получаю: Invalid update column name “Fam”

2. Можно ли сделать так, чтобы после GROUP BY не перечислять все поля TData, а просто указать таблицу TData? В хелпе вычитал такое:
[GROUP BY Column_List_Item [, ...] ]
Parameters
Column_List_Item
Specifies one or more columns used to group rows returned by the query.
Column_List_Item can be one of the following:
- A field in a table in the FROM clause or a subquery.
- A table alias from the SQL SELECT list.
- A numeric expression indicating the location of the column in the result table. The leftmost column is number 1.

Что означает “A table alias from the SQL SELECT list.”? Так можно указать таблицу, или нет?



Исправлено 1 раз(а). Последнее : spammail_88, 10.11.18 14:45
Ratings: 0 negative/0 positive


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

On-line: 9 (Гостей: 9)

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