DM
Гость
|
|
« : 27-09-2004 14:01 » |
|
Проблема в том что функция SUM работает только с числовыми типами данных , а мне надо в селекте выбрать сумму строк (простая конкатенация). Select - обычный запрос c GROUP BY. Если бы был числовой тип, то SUM дала бы арифметическую сумму, а мне то надо "сложить" строки ... Может можно свою БД-функцию сделать? Но надо чтобы она работала в самых разных селектах с разными таблицами и WHERE условиями. Общее у селектов - только GROUP BY и тип колонки - строковый. Может решения нет и надо каждый раз организовывать цикл, внутри которого клеить строки? Не хотелось бы ( P.S. БД - Microsoft SQL Server
|
|
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #1 : 27-09-2004 17:41 » |
|
DM, задача не совсем понятна. Есть тип данных varchar или nvarchar. Их размеры ограничены 8К и 4К символами. Конкатенация строк в групповом операторе SUM, чтобы быть универсальной, должна предполагать размер результата типа text (2 Гб), а для типа text вообще не применяться. Естественно, такой операции нет и в обозримом будущем не будет - слишком узок класс задач и ограничен объём данных (число записей), для которых такая операция в рамках указанных ограничений была бы полезна.
Кстати, опиши задачу, возможно, ты её не так решаешь или создал неудобную структуру данных - может подкину идеи других решений.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
DM
Гость
|
|
« Ответ #2 : 28-09-2004 08:06 » |
|
dimka, тип данных - nvarchar. Причем строки короткие и их немного, результат конкатенации априори не будет больше 4000 символов. Структуру данных создал не я и менять ее не могу . Другие решения, конечно, есть, но все они менее удобные. Я надеялся на какую нибудь идейку в плане хранимых процедур, но, наверное, это нереализуемо. Задачу описывать неинтересно, если решения на данный вопрос нет, ее действительно придется делать совсем подругому.
|
|
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #3 : 28-09-2004 08:32 » |
|
DM, не, ну хранимую процедуру написать можно, но это будет тот самый цикл, который тебе не нравится.
Курсором бежишь по записям и складываешь. И будет на стороне сервера, а не на клиенте.
Я просто объяснил, почему такой функции нет и пока что не будет.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
DM
Гость
|
|
« Ответ #4 : 28-09-2004 09:18 » |
|
А можно ли вызывать хранимую процедуру из селекта? Мне надо чтоб был select обязательно, это ограничение такое дурацкое, но непреодолимое .
|
|
|
Записан
|
|
|
|
DM
Гость
|
|
« Ответ #5 : 28-09-2004 09:59 » |
|
Вроде как user-defined function можно вызывать из селекта, а в саму функцию передать те же самые FROM и WHERE, которые будут в самом селекте. Попробую ...
|
|
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #6 : 28-09-2004 14:38 » |
|
Из select хранимую процедуру не вызовешь, так как в общем случае заранее неизвестен результат процедуры (таблица, множество таблиц или скалярное значение) - черевато ошибками в runtime, можно лишь insert exec сделать - специально для возможности обработки результатов хранимых процедур через временные таблицы.
Ещё раз прошу, опиши задачу - возможно, есть другое решение и одним запросом или процедурой. Мне просто интересно, какая такая задача может потребовать сложения строк в select, да ещё не простое, а с какими-то условиями.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Sla
|
|
« Ответ #7 : 28-09-2004 15:05 » |
|
Пример могу сказать получить текст сообщения , которое заранее отформатированное по полям или по к-л правилу например ID Field1 Val 10 адрес хххххх ID Field2 Val 10 город ннннннн ID Field3 Val 10 лицо сссссссссс и все это в одной таблице
|
|
|
Записан
|
Мы все учились понемногу... Чему-нибудь и как-нибудь.
|
|
|
Anonymous
Гость
|
|
« Ответ #8 : 28-09-2004 15:44 » |
|
Удалось все оформить в виде user-defined function, и вроде заработало, правда пока в несколько упрощенном виде. Описать задачу ... Да... непросто, но попробую раз интересно. Есть некая оболочка (доморощенная, но не мной писаная). Она строит объекты по некоторым описаниям, в том числе должен быть указан источник данных - select. В результате может быть создан, например реестр деталей. Этот реестр отображается в гриде на форме. Туда же можно пихнуть кнопки каких-то операций, а к нопкам привязать методы. Все это делается из этой оболочки, код на языке никакой не пишется. Для особо нестандартных случаев можно и свой код в Visual Studio написать и присандалить. Ну вот и потребовалось сделать несколько десятков объектов, для которых несколько экранных строк соответсвуют большему числу реальных строк. В селекте это достигается элементарной группировкой. Сам селект указывается в виде источника данных в этой оболочке. Проблема начинается дальше - экранные строки надо раскрывать, т.е. высветить, например, все реальные строки из БД для одной какой-то строки экрана. Или пользователь отметит 3 строчки и захочет удалить их. Для этого легко и просто подключить свой код на C#. Но что получит в распоряжение код? - правильно, только то, что было выбрано в данном селекте. А селект только один и указывается в оболочке и никак иначе. Вот и возникла идея склеить все ключи для каждой строки SELECT GROUP BY в одну строчку, а ее то и передать в свой блок кода. Эту строчку можно разобрать и выделить все содержащиеся в ней ключи , однозначно идентифицировав все нужные строчки датабазной таблицы. В этом то и цель. Тут еще важно, что новых строк принципиально заводится не может, только просмотр и удаление. А объектов таких много, у каждого свои WHERE и разные колоноки группировки и число оных разное, в общем не хочется селекты дублировать. Пусть сидят только в одном месте - в источнике данных, а он в яйце, то биш в оболочке.
|
|
|
Записан
|
|
|
|
DM
Гость
|
|
« Ответ #9 : 28-09-2004 15:59 » |
|
Гость это я, забыл зарегистрироваться. Sla, мне не форматировать надо строки , а просто склеить. Как это делает функция SUM для чисел: SELECT group_id, SUM(netto_weight) FROM table_name GROUP BY group_id Только вместо float - nvarchar, а вместо операции суммирования- конкатенация строк. Но спасибо всем, проблема решилась.
|
|
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #10 : 29-09-2004 11:09 » |
|
Как происходит "высвечиваение строк" из таблицы, соответствующих одной экранной строке? - проблема решается дополнительным select'ом, когда ты разворачиваешь группу по известному общему для них идентификатору экранной строки (groupid в данном случае) или какому угодно - в любом случае он есть! Зачем извлекать все данные из базы сразу? Если появилась потребность, значит ты эту свою оболочку расширил функцией раскрытия группы - вот тутда и вставь дополнительный select.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
DM
Гость
|
|
« Ответ #11 : 29-09-2004 12:49 » |
|
dimka, кому известен это groupid Он же указывается в запросе, а запрос указывается в оболочке. Программа может получить доступ к полям, которые выберуться в результате работы запроса. И все. Поэтому и важно, чтобы в одном из полей результата селекта сидело что-то, что однозначно идентифицирует группу. Но дискуссия стала слишком частной, давай здесь ее закроем. Если очень хочется, побеседуем лично .
|
|
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #12 : 29-09-2004 15:06 » |
|
ничего не частной - всё равно в этой теме продолжения не будет, поэтому можно и здесь Т.е. ты имеешь в распоряжении своём только выборку для основной экранной таблицы и всё... И из этих данных (причём в общем случае) надо суметь развернуть группу... Вот теперь задача сформулирована, и её можно попробовать решать . Пойду подумаю .
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Anonymous
Гость
|
|
« Ответ #13 : 30-09-2004 06:46 » |
|
dimka, спасибо за участие . Но поместить идентификатор группы в результат селекта можно только 2-мя способами: 1) Включить все атрибуты GROUP BY в select и пометить их как-то, например задав специальные имена. Это можно сделать без особых хитростей, но для меня это неудобно (группы очень разнообразны). 2) Каким-то образом склеить все ключи для группы в строку через разделитель, например, пробел. Благо ключ всегда целчисленный ID c фиксированным именем. Это, конечно, грязный вариант, просто в данном конкретном случае для меня он удобен. Тут была бы идеальна функция SUM для строк. Жаль, что ее нет . Если надумаешь что-то кардинально иное - :l_wink:
|
|
|
Записан
|
|
|
|
DM
Гость
|
|
« Ответ #14 : 30-09-2004 06:54 » |
|
А сделал я так - загнал селекты в функцию, возвращающую таблицу. В функции в цикле клею ключи в строку. Все работает как хотелось. Так что, dimka, интерес остался чисто спортивный.
|
|
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #15 : 04-10-2004 14:23 » |
|
В общем случае задача развёртывания группы не решается - восстановить нельзя. Но ты вводишь дополнительное поле, где хранишь идентификаторы - значит имеешь доступ к исходным запросам. Можно в виде строки в дополнительном поле хранить запрос на раскрытие группы. В общем, плохая архитектура, но такова участь программиста на этапе сопровождения
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
DM
Гость
|
|
« Ответ #16 : 06-10-2004 09:46 » |
|
dimka, а как этот запрос на раскрытие группы загнать в результат селекта? Результат селекта - несколько строк, и для каждой строки конкретные значения полей, идентифицирующие группу - свои. И значения эти - собственно результат селекта. Поэтому такой запрос по сути своей будет просто перечислением параметров. А значения параметров - это значения полей, результат исходного селекта. В общем-то это я и предлагал в качестве альтернативного варианта раньше. Или ты что-то иное имеешь ввиду ?
|
|
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #17 : 06-10-2004 10:04 » |
|
допустим, простейший случай запроса главной таблицы: select sum(total), year from table group by year отсюда следует, что раскрытие конкретной группы будет выглядеть так: select total, year from table where year = @year где @year - параметр, извлекаемый из той конкретной строчки, в которую тыкнулся юзер в таком случае окончательно запрос главной таблицы будет выглядеть так select sum)t.total: as sum, t.year, 'select t.total, t.year from table t where t.year = ' + convert)varchar, t.year: as grqry from table t group by t.year
здесь ты сразу раскрываешь параметр, т.е. остаётся исполнить запрос из поля grqry без каких-либо дополнительных преобразований. как выше сказано, если у тебя несколько параметров группировки, то они разворачиваются так исходное group by year, month разворот группы where year = @year and month = @month вот что я имел ввиду
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
DM
Гость
|
|
« Ответ #18 : 06-10-2004 13:32 » |
|
Действительно, сразу сформировать строку WHERE прямо в селекте - свежая мысль :idea: . Уже вижу, где мне это пригодится, спасибо :l_wink:
|
|
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #19 : 06-06-2005 16:08 » |
|
Увидел-таки решение первой задачи, сформулированной в этой теме, для SQLServer, без курсора и не для использования в GROUP BY, хотя можно через UDF реализовать и в запросах с GROUP BY. DECLARE @T nvarchar(4000) SET @T = ''
SELECT @T = @T + (CASE WHEN LEN(@T) > 0 THEN ', ' ELSE '' END) + xtype FROM sysobjects
PRINT @T
|
|
« Последнее редактирование: 20-12-2007 20:41 от Алексей1153++ »
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
sagarkov
Гость
|
|
« Ответ #20 : 12-11-2009 08:40 » |
|
А можно сделать так же в MySQL 5.1?
|
|
|
Записан
|
|
|
|
Sla
|
|
« Ответ #21 : 12-11-2009 08:44 » |
|
sagarkov, что реализовать?
зы. Тема довольно старая, поэтому - опиши задачу.
|
|
|
Записан
|
Мы все учились понемногу... Чему-нибудь и как-нибудь.
|
|
|
sagarkov
Гость
|
|
« Ответ #22 : 12-11-2009 09:02 » |
|
Мне нужно конкатенировать строки внутри группы после операции group by. Пишу что-то вроде: SET @path:=''; SELECT @path := concat_ws('|', @path, subject) as path2, count(*), phone from MessageLog group by phone; но не работает.
|
|
|
Записан
|
|
|
|
RXL
|
|
« Ответ #23 : 12-11-2009 14:58 » |
|
В MySQL есть групповая функция для конткатенации - GROUP_CONCAT(). SELECT GROUP_CONCAT(CONCAT(a, ' ', b, ' ', c) ORDER BY a SEPARATOR ';') FROM tab;
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #24 : 12-11-2009 15:06 » |
|
а что значит SEPARATOR ';'
|
|
|
Записан
|
|
|
|
RXL
|
|
« Ответ #25 : 13-11-2009 04:53 » |
|
Леш, а по смыслу что это значит? По словарю: "SEPARATOR" - "разделитель". Значит разделяет он объединяемые элементы.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #26 : 13-11-2009 05:07 » |
|
ну значение слова то я знаю
то есть должно получиться
a; ;b; ;c
а я полагал, автору надо a b c
|
|
|
Записан
|
|
|
|
RXL
|
|
« Ответ #27 : 13-11-2009 06:09 » |
|
Дык, я только пример дал - дальше уж делай что хошь...
И, кстати, ты неверно интерпретировал. Будет: a1 b1 c1;a2 b2 c2;a3 b3 c3...
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
|