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

Дана такая таблица:
c1c2c3c4c11c22c33
acyvacv
acyvacu
acyvbdv
acyvbdu
bdyvacv

Вопрос: Как найти в ней одинаковые записи и удалить их, при условии что столбцы c1 и c11, c2 и c22, ... имеют одинаковый тип? (Например в этой таблице строка #3 и #5 равны)
Думал про объединение этих столбцов, но как тогда решить проблему ab = ba?
4 апр 15, 20:26    [17474125]     Ответить | Цитировать Сообщить модератору
 Re: Поиск в таблице  [new]
ЦБ
Member [заблокирован]

Откуда:
Сообщений: 2773
0404
Думал про объединение этих столбцов, но как тогда решить проблему ab = ba?

Так можно
 case when c1<c11 then c1+c11 else c11+c1 end as c1
4 апр 15, 22:17    [17474343]     Ответить | Цитировать Сообщить модератору
 Re: Поиск в таблице  [new]
o-o
Guest
ЦБ
0404
Думал про объединение этих столбцов, но как тогда решить проблему ab = ba?

Так можно
 case when c1<c11 then c1+c11 else c11+c1 end as c1

в общем случае не прокатит,
если односимвольное поле, то ок, а если нет?
вот такие строки не равны в смысле задания ТС:
('b', 'd', 'y', 'v', 'bd', 'c', 'v')
('bb', 'd', 'y', 'v', 'd', 'c', 'v')

а ваше выражение case when c1<c11 then c1+c11 else c11+c1 end as c1
даст одинаковое bbd

вот формально правильный и дотошный, но зато монстр:
declare @t table (id int identity, c1 varchar(10), c2 varchar(10), c3 varchar(10), 
                  c4 varchar(10), c11 varchar(10), c22 varchar(10), c33 varchar(10))
insert into @t(c1, c2, c3, c4, c11, c22, c33) values
('a',	'c',	'y',	'v',	'a',	'c',	'v'),
('a',	'c',	'y',	'v',	'a',	'c',	'u'),
('a',	'c',	'y',	'v',	'b',	'd',	'v'),
('a',	'c',	'y',	'v',	'b',	'd',	'u'),
('b',	'd',	'y',	'v',	'a',	'c',	'v'),
('b',	'd',	'y',	'v',	'bd',	'c',	'v'),
('bb',	'd',	'y',	'v',	'd',	'c',	'v'),
('bb',	'd',	'y',	'v',	'd',	'c',	'v')

select t1.id, t2.id
from @t t1 left join @t t2 on (t1.c1 = t2.c1 or ((t1.c1 = t2.c11) and (t1.c11 = t2.c1))) and 
                              (t1.c2 = t2.c2 or ((t1.c2 = t2.c22) and (t1.c22 = t2.c2))) and
                              (t1.c3 = t2.c3 or ((t1.c3 = t2.c33) and (t1.c33 = t2.c3))) and
                               t1.c4 = t2.c4 and
                              (t1.c11 = t2.c11 or ((t1.c11 = t2.c1) and (t1.c1 = t2.c11)))and
                              (t1.c22 = t2.c22 or ((t1.c22 = t2.c2) and (t1.c2 = t2.c22)))and
                              (t1.c33 = t2.c33 or ((t1.c33 = t2.c3) and (t1.c3 = t2.c33)))and
                               t1.id < t2.id
where t2.id is not null
---
3	5
7	8  
5 апр 15, 01:55    [17474896]     Ответить | Цитировать Сообщить модератору
 Re: Поиск в таблице  [new]
ЦБ
Member [заблокирован]

Откуда:
Сообщений: 2773
o-o
в общем случае не прокатит
Согласен.
Тогда можно с разделителем, в виде какого-нибудь непечатного слова :) символа,
и, которого, заведомо не будет в данных.
Типа так
declare @t table (id int identity, c1 varchar(2),c2 varchar(2),c3 varchar(2),c4 varchar(2),c11 varchar(2),c22 varchar(2),c33 varchar(2))

insert into @t (c1,c2,c3,c4,c11,c22,c33)

select 'a','c','y','v','a','c','v' union all
select 'a','c','y','v','a','c','u' union all
select 'a','c','y','v','b','d','v' union all
select 'a','c','y','v','b','d','u' union all
select 'b','d','y','v','a','c','v' union all
select 'b','d','y','v','bd','c','v' union all
select 'bb','d','y','v','d','c','v' union all
select 'bb','d','y','v','d','c','v'

declare @delim char
set @delim=char(1)

select min (id) as id 
	,case when c1<c11 then c1+@delim+c11 else c11+@delim+c1 end as c1
	,case when c2<c22 then c2+@delim+c22 else c22+@delim+c2 end as c2
	,case when c3<c33 then c3+@delim+c33 else c33+@delim+c3 end as c3
	,c4
 from @t
group by
	 case when c1<c11 then c1+@delim+c11 else c11+@delim+c1 end
	,case when c2<c22 then c2+@delim+c22 else c22+@delim+c2 end
	,case when c3<c33 then c3+@delim+c33 else c33+@delim+c3 end
	,c4
order by 1
5 апр 15, 09:05    [17475100]     Ответить | Цитировать Сообщить модератору
 Re: Поиск в таблице  [new]
0404
Guest
автор
в общем случае не прокатит

Все верно, столбцы могут иметь разные типы, но попарно типы будут одинаковы. Я для простоты примера сделал их односимвольными.
автор
вот формально правильный и дотошный, но зато монстр:

Монстр верен, но это частный случай. Как быть если в такой таблице 1000 записей? Существует ли общее решение данной задачи?
5 апр 15, 09:43    [17475128]     Ответить | Цитировать Сообщить модератору
 Re: Поиск в таблице  [new]
o-o
Guest
ЦБ,
ТС подтвердил, что типы попарно одинаковы, но необязательно варчары.
что будем делать с числами?
ведь любую сумму S можно разложить на 2 слагаемых бесконечным числом способов: (S-a, S+a)
declare @t table (id int identity, c1 int,c2 varchar(2),c3 varchar(2),c4 varchar(2),c11 int,c22 varchar(2),c33 varchar(2))

insert into @t (c1,c2,c3,c4,c11,c22,c33)

select 1,'c','y','v',1,'c','v' union all
select 1,'c','y','v',1,'c','u' union all
select 1,'c','y','v',2,'d','v' union all
select 1,'c','y','v',2,'d','u' union all
select 2,'d','y','v',1,'c','v' union all
select 2,'d','y','v',8,'c','v' union all
select 3,'d','y','v',7,'c','v' union all
select 2,'d','y','v',8,'c','v'

declare @delim char
set @delim=char(1)

select min (id) as id 
	,case when c1<c11 then c1+c11 else c11+c1 end as c1
	,case when c2<c22 then c2+@delim+c22 else c22+@delim+c2 end as c2
	,case when c3<c33 then c3+@delim+c33 else c33+@delim+c3 end as c3
	,c4
 from @t
group by
	 case when c1<c11 then c1+c11 else c11+c1 end
	,case when c2<c22 then c2+@delim+c22 else c22+@delim+c2 end
	,case when c3<c33 then c3+@delim+c33 else c33+@delim+c3 end
	,c4
order by 1
---
id	c1	c2	c3	c4
1	2	cc	vy	v
2	2	cc	uy	v
3	3	cd	vy	v
4	3	cd	uy	v
6	10	cd	vy	v

/* monster */

select t1.id, t2.id
from @t t1 left join @t t2 on (t1.c1 = t2.c1 or ((t1.c1 = t2.c11) and (t1.c11 = t2.c1))) and 
                              (t1.c2 = t2.c2 or ((t1.c2 = t2.c22) and (t1.c22 = t2.c2))) and
                              (t1.c3 = t2.c3 or ((t1.c3 = t2.c33) and (t1.c33 = t2.c3))) and
                               t1.c4 = t2.c4 and
                              (t1.c11 = t2.c11 or ((t1.c11 = t2.c1) and (t1.c1 = t2.c11)))and
                              (t1.c22 = t2.c22 or ((t1.c22 = t2.c2) and (t1.c2 = t2.c22)))and
                              (t1.c33 = t2.c33 or ((t1.c33 = t2.c3) and (t1.c3 = t2.c33)))and
                               t1.id < t2.id
where t2.id is not null
---
3	5
6	8
5 апр 15, 11:23    [17475227]     Ответить | Цитировать Сообщить модератору
 Re: Поиск в таблице  [new]
o-o
Guest
0404
Монстр верен, но это частный случай. Как быть если в такой таблице 1000 записей? Существует ли общее решение данной задачи?

для монструозной архитектуры надо генерить динамического монстра.
например, написать процедуру с табличным параметром в виде пар колонок,
пусть собирет динамику.
условие же однотипное, знай себе пары столбцов подставляй.
оставшиеся столбцы в пойдут в виде чистого равенства.
процедуру заставить писать проектировщика
5 апр 15, 11:31    [17475244]     Ответить | Цитировать Сообщить модератору
 Re: Поиск в таблице  [new]
o-o
Guest
0404
Монстр верен, но это частный случай. Как быть если в такой таблице 1000 записей? Существует ли общее решение данной задачи?

ой!
так 1000 записей или 1000 столбцов?
1000 записей монстра не смущают :)
5 апр 15, 11:33    [17475248]     Ответить | Цитировать Сообщить модератору
 Re: Поиск в таблице  [new]
0404
Guest
o-o,

Да, поправочка:) : Столбцов может быть существенно больше
5 апр 15, 12:06    [17475321]     Ответить | Цитировать Сообщить модератору
 Re: Поиск в таблице  [new]
ЦБ
Member [заблокирован]

Откуда:
Сообщений: 2773
0404
o-o,

Да, поправочка:) : Столбцов может быть существенно больше
продолжим про "монстров" :)

Тут, какбэ, кол-во "столбов" никак не ограниченно, и с каждым отдельным столбцом "разбираться" не нужно.
Единственное, что столбцы, для которых есть "столбцы аналоги" (те, которые "имеют одинаковый тип"), должны называться по какому-то правилу (у меня это c1==>c1_)
Или нужна табличка соответствия
ИмяПоляИмяПоляАналога
c1Field100500
с такой табличкой даже попроще будет ...

declare @t table (id int, c1 varchar(2), c2 int, c3 varchar(2), c4 varchar(2), c1_ varchar(2), c2_ int, c3_ varchar(2))
declare @xml xml

insert into @t (id,c1,c2,c3,c4,c1_,c2_,c3_)

select 1,'a',3,'y','v','a',3,'v' union all
select 2,'a',3,'y','v','a',3,'u' union all
select 3,'a',3,'y','v','b',4,'v' union all
select 4,'a',3,'y','v','b',4,'u' union all
select 5,'b',4,'y','v','a',3,'v' union all
select 6,'b',4,'y','v','bd',3,'v' union all
select 7,'bb',4,'y','v','d',3,'v' union all
select 8,'bb',4,'y','v','d',3,'v'

declare @delim char
set @delim=char(1)
--
	
set @xml = (select * from @t for xml raw, elements, type)

--select @xml

;with cte as 
(
	select t.c.value('../id[1]/text()[1]', 'int') as id, a.fieldname, a.fieldvalue 
	from @xml.nodes('/row/*') as t(c)
	cross apply 
			(select 
				 t.c.value('local-name(.)', 'varchar(20)') as fieldname
				,t.c.value('./text()[1]', 'varchar(20)') as fieldvalue
			 where t.c.value('local-name(.)', 'varchar(20)') <> 'id') a
),
cte1 as
(
	select	t1.id, t1.fieldname, case when t1.fieldvalue<t2.fieldvalue then t1.fieldvalue else t2.fieldvalue end as fieldvalue
	from cte t1 inner join cte t2 on t1.id=t2.id and t1.fieldname=t2.fieldname+'_'

	union all

	select	t1.id, t1.fieldname, case when t1.fieldvalue>t2.fieldvalue then t1.fieldvalue else t2.fieldvalue end as fieldvalue
	from cte t1 inner join cte t2 on t1.id=t2.id and t1.fieldname+'_'=t2.fieldname

	union all

	select	t1.id, t1.fieldname, t1.fieldvalue
	from cte t1
	where	not exists(select 1 from cte t2 where t1.id=t2.id and t2.fieldname=t1.fieldname+'_')
	  and	t1.fieldname not like '%[_]'
),
cte2 as
(
	select t.id, 
		(select fieldvalue+@delim as 'data()' from cte1 where t.id=cte1.id order by cte1.fieldname for xml path('')) as flag
	from @t t
)

select min(id) as id --, flag  
from cte2
group by flag
order by 1

id
-----------
1
2
3
4
6
7
5 апр 15, 22:26    [17476746]     Ответить | Цитировать Сообщить модератору
 Re: Поиск в таблице  [new]
ЦБ
Member [заблокирован]

Откуда:
Сообщений: 2773
o-o
ЦБ,
ТС подтвердил, что типы попарно одинаковы, но необязательно варчары.

Даа, и вопрос с типами, "походу дела", решается автоматически, так как всё приводим к varchar
5 апр 15, 22:31    [17476755]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить