Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Можно ли сделать аналог агрегатной функции SUM для строк ?  (Прочитано 46440 раз)
0 Пользователей и 1 Гость смотрят эту тему.
DM
Гость
« : 27-09-2004 14:01 » 

Проблема в том что функция SUM работает только с числовыми типами данных Жаль, а мне надо в селекте выбрать сумму строк (простая конкатенация). Select - обычный запрос c GROUP BY. Если бы был числовой тип, то SUM дала бы арифметическую сумму, а мне то надо "сложить" строки ...  Может можно свою БД-функцию сделать? Но надо чтобы она работала в самых разных селектах с разными таблицами и WHERE условиями. Общее у селектов - только GROUP BY и тип колонки - строковый.  Может решения нет и надо каждый раз организовывать цикл, внутри которого клеить строки? Не хотелось бы Жаль(
P.S.  БД - Microsoft SQL Server
Записан
Dimka
Деятель
Команда клуба

ru
Offline 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
Деятель
Команда клуба

ru
Offline 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
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #6 : 28-09-2004 14:38 » 

Из select хранимую процедуру не вызовешь, так как в общем случае заранее неизвестен результат процедуры (таблица, множество таблиц или скалярное значение) - черевато ошибками в runtime, можно лишь insert exec сделать - специально для возможности обработки результатов хранимых процедур через временные таблицы.

Ещё раз прошу, опиши задачу - возможно, есть другое решение и одним запросом или процедурой. Мне просто интересно, какая такая задача может потребовать сложения строк в select, да ещё не простое, а с какими-то условиями.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Sla
Команда клуба

ua
Offline Offline
Пол: Мужской

WWW
« Ответ #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
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #10 : 29-09-2004 11:09 » 

Как происходит "высвечиваение строк" из таблицы, соответствующих одной экранной строке? - проблема решается дополнительным select'ом, когда ты разворачиваешь группу по известному общему для них идентификатору экранной строки (groupid в данном случае) или какому угодно - в любом случае он есть! Зачем извлекать все данные из базы сразу? Если появилась потребность, значит ты эту свою оболочку расширил функцией раскрытия группы - вот тутда и вставь дополнительный select.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
DM
Гость
« Ответ #11 : 29-09-2004 12:49 » 

dimka, кому известен это groupid Не понял Он же указывается в запросе, а запрос указывается в оболочке. Программа может получить доступ к полям, которые выберуться в результате работы запроса. И все. Поэтому и важно, чтобы в одном из полей результата селекта сидело что-то, что однозначно идентифицирует группу.  Но дискуссия стала слишком частной, давай здесь ее закроем. Если очень хочется, побеседуем лично  Ага .
Записан
Dimka
Деятель
Команда клуба

ru
Offline 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
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #15 : 04-10-2004 14:23 » 

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

Можно в виде строки в дополнительном поле хранить запрос на раскрытие группы.

В общем, плохая архитектура, но такова участь программиста на этапе сопровождения Жаль
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
DM
Гость
« Ответ #16 : 06-10-2004 09:46 » 

dimka, а как этот запрос на раскрытие группы загнать в результат селекта? Результат селекта - несколько строк, и для каждой строки конкретные значения полей, идентифицирующие группу - свои. И значения эти - собственно результат селекта. Поэтому такой запрос по сути своей будет просто перечислением параметров. А значения параметров - это значения полей, результат исходного селекта. В общем-то это я и предлагал в качестве альтернативного варианта раньше.  Или ты что-то иное имеешь ввиду   Вот такой я вот ?
Записан
Dimka
Деятель
Команда клуба

ru
Offline 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
Деятель
Команда клуба

ru
Offline 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
Команда клуба

ua
Offline Offline
Пол: Мужской

WWW
« Ответ #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
Технический
Администратор

Offline Offline
Пол: Мужской

WWW
« Ответ #23 : 12-11-2009 14:58 » 

В MySQL есть групповая функция для конткатенации - GROUP_CONCAT().

Код:
SELECT GROUP_CONCAT(CONCAT(a, ' ', b, ' ', c) ORDER BY a SEPARATOR ';') FROM tab;
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #24 : 12-11-2009 15:06 » 

а что значит
SEPARATOR ';'
Записан

RXL
Технический
Администратор

Offline Offline
Пол: Мужской

WWW
« Ответ #25 : 13-11-2009 04:53 » 

Леш, а по смыслу что это значит? Улыбаюсь По словарю: "SEPARATOR" - "разделитель". Значит разделяет он объединяемые элементы.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #26 : 13-11-2009 05:07 » 

ну значение слова то я знаю

то есть должно получиться

a; ;b; ;c

а я полагал, автору надо
a b c
Записан

RXL
Технический
Администратор

Offline Offline
Пол: Мужской

WWW
« Ответ #27 : 13-11-2009 06:09 » new

Дык, я только пример дал - дальше уж делай что хошь...

И, кстати, ты неверно интерпретировал. Будет: a1 b1 c1;a2 b2 c2;a3 b3 c3...
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines