Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Помогите пожалуйста написать запрос.  [new]
ProBiotek
Member

Откуда: Moscow
Сообщений: 907
Привет.

Подскажите пожалуйста как правильно написать следующий запрос. Имеется такая таблица

IdStrParentId Show
'1' null true
'1.1''1'null
'1.2''1'null
'2' nullfalse
'2.1''2'null
'2.2''2'null


Нужно, чтобы вы финальную выборку попали строки у которых Show ==true. При этом те строки, у которых parentId не Null, должны брать этот параметр у "родителя".

Т.е. в данном примере в финальную выборку должны попасть первые 3 строки (родительская и две подчиненные).

Подскажите пожалуйста, как такое закрутить.
9 мар 16, 19:01    [18912593]     Ответить | Цитировать Сообщить модератору
 Re: Помогите пожалуйста написать запрос.  [new]
Glory
Member

Откуда:
Сообщений: 104751
ProBiotek
Подскажите пожалуйста, как такое закрутить.

Это называется рекурсивный запрос
Для всех вершин с Show ==true нужно просто построить иерархию
9 мар 16, 19:04    [18912602]     Ответить | Цитировать Сообщить модератору
 Re: Помогите пожалуйста написать запрос.  [new]
ProBiotek
Member

Откуда: Moscow
Сообщений: 907
Мне кажется нужно сделать селф-джойн выборки через tab1.ParentId Like '%'+tab2.idStr. А в tab2 сделать простую выборку строк, где ParentId is null.

Правильно ли я понимаю ? Мне очень не нравится идея с "Like '%'+tab2.idStr", но другого варианта придумать не могу. Поэтому и спрашиваю.
9 мар 16, 19:06    [18912607]     Ответить | Цитировать Сообщить модератору
 Re: Помогите пожалуйста написать запрос.  [new]
Knyazev Alexey
Member

Откуда: Екб -> Мск
Сообщений: 10233
Блог


К сообщению приложен файл. Размер - 18Kb
9 мар 16, 19:08    [18912617]     Ответить | Цитировать Сообщить модератору
 Re: Помогите пожалуйста написать запрос.  [new]
Glory
Member

Откуда:
Сообщений: 104751
ProBiotek
Правильно ли я понимаю ? Мне очень не нравится идея с "Like '%'+tab2.idStr", но другого варианта придумать не могу. Поэтому и спрашиваю.

Вам нужно в хелпе набрать Recursive Queries Using Common Table Expressions и научиттся писать рекурсивные запросы
9 мар 16, 19:10    [18912623]     Ответить | Цитировать Сообщить модератору
 Re: Помогите пожалуйста написать запрос.  [new]
ProBiotek
Member

Откуда: Moscow
Сообщений: 907
Knyazev Alexey,

Большое спасибо !!
9 мар 16, 19:13    [18912627]     Ответить | Цитировать Сообщить модератору
 Re: Помогите пожалуйста написать запрос.  [new]
ProBiotek
Member

Откуда: Moscow
Сообщений: 907
Разрешите усложнить задача, так как она сейчас стоит передо мной :)


DataTable
IdStrShow
'1' true
'1.1' null
'1.2' null
'2.1' false
'2.1.1' null
'2.1.2' null


RootNodes
RootId
'1'
'2.1'



Задача стоит та же самая:
имеется 2 таблицы. В первой все данные, а во второй имеется набор "рутовых корней".

Так вот, нужно вывести те данные, у родителей которых указано Show==true.

Т.е. по сути у меня нету поля Parent явно. родительство определяется лишь строкой IdStr. Где '1.1' является родителем для '1.1.1' и т.д.
При этом есть отдельная таблица, которая и задает эти "Рутовые записи", на которые и нужно ориентироватся - т.е. вывести их их детей.
Также замечу, что глубокой иерархии нету. Нужно ориентироваться только на Рутовые корни. И все их дети должны выводится в зависимости от этого.


Что скажете ? По сути зада именно такая передо мной сейчас. Я зря в первой запросе ввел поле parentId.... Извините.
9 мар 16, 19:37    [18912680]     Ответить | Цитировать Сообщить модератору
 Re: Помогите пожалуйста написать запрос.  [new]
ProBiotek
Member

Откуда: Moscow
Сообщений: 907
Имея на руках решение Knyazev Alexey, я сейчас пришел к такому решении, но застрял.

declare @t table (IdStr varchar (5), Show varchar (5))
insert into @t 
values ('1', 'true'),
('1.1', 'true'),
('1.2', 'false'),
('2', 'false'),
('2.1', 'true'),
('2.2', 'false');



with RootNodes as (
  select '1' as RootNode
  union all 
  select '2' as RootNode  
)

,ParentNodes as (
  select IdStr, Show
  from @t
  where Show in (select RootNode from RootNodes)
)

,ResultNodes as (
  select *
  from data
  where IdStr like   <<< ?? Как вывести все записи, но заглядывая на родителя  ?
)



Помогите пожалуйста.
9 мар 16, 19:41    [18912685]     Ответить | Цитировать Сообщить модератору
 Re: Помогите пожалуйста написать запрос.  [new]
Glory
Member

Откуда:
Сообщений: 104751
ProBiotek
Т.е. по сути у меня нету поля Parent явно. родительство определяется лишь строкой IdStr. Где '1.1' является родителем для '1.1.1' и т.д.

И каким же образом "оно является" ?
9 мар 16, 19:43    [18912690]     Ответить | Цитировать Сообщить модератору
 Re: Помогите пожалуйста написать запрос.  [new]
ProBiotek
Member

Откуда: Moscow
Сообщений: 907
т.е. такое решение у меня сейчас. на чем и застрял

with RootNodes as (
  select '1' as RootNode
  union all 
  select '2' as RootNode  
)

,ParentNodes as (
  select IdStr, Show
  from @t
  where Show in (select RootNode from RootNodes)
)

,ResultNodes as (
  select d.*
  from @t d
  join ParentNodes pn on d.IdStr like d.IdStr+'%'   << похоже тут жестко туплю
)
9 мар 16, 19:46    [18912696]     Ответить | Цитировать Сообщить модератору
 Re: Помогите пожалуйста написать запрос.  [new]
ProBiotek
Member

Откуда: Moscow
Сообщений: 907
Glory
И каким же образом "оно является" ?


Родительство определяется исключительно по строке.
Имеется жестко заданный список "родителей": '1', '2'

Нужно вывести Родителей и их Детей - беря параметр Show родителя.

Родительство определяется так: все записи вида "1.1.1", "1.1.3.", "1.3.1.1.1.1.1.1.1.1.1." являются детьми записи "1.1", и должны брать ее свойство Show


Вот так сейчас задача стоит передо мной...
9 мар 16, 19:49    [18912698]     Ответить | Цитировать Сообщить модератору
 Re: Помогите пожалуйста написать запрос.  [new]
Glory
Member

Откуда:
Сообщений: 104751
ProBiotek
Родительство определяется исключительно по строке.

Каким образом ?
Вы смотрите на каждую запись и лично решаете, кто чьим потомком/родителм является ?
9 мар 16, 19:50    [18912703]     Ответить | Цитировать Сообщить модератору
 Re: Помогите пожалуйста написать запрос.  [new]
ProBiotek
Member

Откуда: Moscow
Сообщений: 907
Glory,

Родительство определяется через like.

Из двух строк
'1.1' и '1.1.1' и '1.1.1.1.1.1.1.1.1' вторая и третья будут подчиненной у первой. не третья у второй, а обе у первой ! Иерархия состоит лишь из двух уровней.

Причем сам список этих "родителей" задан жестко (см with RootNodes as)
9 мар 16, 20:07    [18912736]     Ответить | Цитировать Сообщить модератору
 Re: Помогите пожалуйста написать запрос.  [new]
Glory
Member

Откуда:
Сообщений: 104751
ProBiotek
Родительство определяется через like.

Ну так напишите этот like
9 мар 16, 20:09    [18912741]     Ответить | Цитировать Сообщить модератору
 Re: Помогите пожалуйста написать запрос.  [new]
ProBiotek
Member

Откуда: Moscow
Сообщений: 907
Glory,

Так вот же 18912696. не работает :(
9 мар 16, 20:09    [18912742]     Ответить | Цитировать Сообщить модератору
 Re: Помогите пожалуйста написать запрос.  [new]
ProBiotek
Member

Откуда: Moscow
Сообщений: 907
Прошу прощения, у меня там опечатка:

,ParentNodes as (
  select IdStr, Show
  from @t
  where [b]IdStr[/b] in (select RootNode from RootNodes)  
)
9 мар 16, 20:11    [18912746]     Ответить | Цитировать Сообщить модератору
 Re: Помогите пожалуйста написать запрос.  [new]
Glory
Member

Откуда:
Сообщений: 104751
Потому что вот тут 18912617 надо вместо выражение parentid = IdStr написать нужный like
9 мар 16, 20:13    [18912750]     Ответить | Цитировать Сообщить модератору
 Re: Помогите пожалуйста написать запрос.  [new]
ProBiotek
Member

Откуда: Moscow
Сообщений: 907
Glory,

Извините, но тот запрос не подходит. Там настройка на иерархичность данных.

Попробуйте его на этих данных:

declare @t table (IdStr varchar (5), ParentId varchar(5), Show varchar (5))
insert into @t 
values ('1', null,'true'),
('1.1', '1','true'),
('1.2', '1','false'),
('1.1.2', '1','false'),
('2', null,'false'),
('2.1', '2','true'),
('2.2', '2','false');


with cte
as 
(
select * from @t
where Show = 'true' and ParentId is null
union all
select t1.* from @t t1
inner join cte t2
 --on t1.ParentId = t2.IdStr
 on t1.IdStr like t2.IdStr+'_%'
)
select *
from cte


Почему 1.1.2 вывелось дважды ? Не пойму.
9 мар 16, 20:46    [18912847]     Ответить | Цитировать Сообщить модератору
 Re: Помогите пожалуйста написать запрос.  [new]
ProBiotek
Member

Откуда: Moscow
Сообщений: 907
Вы мне скажите, мое это решение 18912696 оно в принципе в верном направлении ? Или я совсем не туда иду ?
9 мар 16, 20:48    [18912850]     Ответить | Цитировать Сообщить модератору
 Re: Помогите пожалуйста написать запрос.  [new]
Knyazev Alexey
Member

Откуда: Екб -> Мск
Сообщений: 10233
Блог
ProBiotek
Почему 1.1.2 вывелось дважды ? Не пойму.


потому, что для 1.1.2 по вашей логике родителем может быть и 1.1 и 1
9 мар 16, 21:19    [18912919]     Ответить | Цитировать Сообщить модератору
 Re: Помогите пожалуйста написать запрос.  [new]
Knyazev Alexey
Member

Откуда: Екб -> Мск
Сообщений: 10233
Блог
declare @t table (IdStr varchar (5), ParentId varchar(5), Show varchar (5))
insert into @t 
values ('1', null,'true'),
('1.1', '1','true'),
('1.2', '1','false'),
('1.1.2', '1','false'),
('2', null,'false'),
('2.1', '2','true'),
('2.2', '2','false');


with cte
as 
(
select 0 as level, * from @t
where Show = 'true' and ParentId is null
union all
select t2.level + 1, t1.* from @t t1
inner join cte t2
 on t1.IdStr like t2.IdStr+'.%'
 and len(t1.IdStr) - len(replace( t1.IdStr,'.','') ) = t2.level + 1
)
select *
from cte
9 мар 16, 21:22    [18912930]     Ответить | Цитировать Сообщить модератору
 Re: Помогите пожалуйста написать запрос.  [new]
tip78
Member

Откуда: Москва
Сообщений: 1266
я всё понимаю, но true/false через varchar это уже перебор
tinyint(1) это бл?*:!!
и юзаешь 0/1
про всё остальное молчу уже
9 мар 16, 21:49    [18913013]     Ответить | Цитировать Сообщить модератору
 Re: Помогите пожалуйста написать запрос.  [new]
ProBiotek
Member

Откуда: Moscow
Сообщений: 907
Knyazev Alexey,

Спасибо большое еще раз ! Я понял, что мне нужно подтянуть знания по SQL. Буду читать, рекурсивные запросы я явно подзабыл уже совсем.
9 мар 16, 22:44    [18913160]     Ответить | Цитировать Сообщить модератору
 Re: Помогите пожалуйста написать запрос.  [new]
ProBiotek
Member

Откуда: Moscow
Сообщений: 907
tip78,

Та это я так таблицу сделал для наглядности (см первый пост), а Knyazev Alexey просто скопипастил в скрипт.
Это просто пример кода, нечего так волноваться :) Конечно никто не пишет в БД булевский тип строкой (ибо потом придется прикручивать UPPER для проверки, ну и размер поля, конечно же, а еще индекс на UPPER-вычисляемое поле).
9 мар 16, 22:48    [18913169]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить