|
Гуру t-sql, поможите кто чем может? | ☑ | ||
---|---|---|---|---|
0
IamAlexy
28.03.12
✎
12:45
|
Собственно есть простенькая задачка:
в MSSQL лежит табличка с парой миллионов записей. Соответственно в одной из колонок заполнена строка вида: "Иванов, Иван, Иванович, 1980, М, Сволочь" "Петров, Сидор, Петрович, 1986, М, Недалекий" и тд. то есть по сути строкой. Нужно это все как то скопировать в другую таблицу, или в эту же в другие колонки то что запятыми разделено типа Иванов | Иван | Иванович | 1980 | M | Сволоч ну и тд.. понятное дело, что 1Сом это сделать можно, проблема в том что как то многовато записей и долговато получается, отсюда вопрос: поделитесь скриптом который можно под себя модифицировать и конвертнуть таблицу эту на SQL сервере непосредственно? |
|||
1
Ёпрст
28.03.12
✎
12:48
|
(0) количество запятых одинаково ?
во сволько колонок нажо запихивать ? |
|||
2
Джинн
28.03.12
✎
12:48
|
||||
3
le_
28.03.12
✎
12:48
|
||||
4
IamAlexy
28.03.12
✎
12:49
|
зы: всякие тематические форумы читал.. но там все примеры типа в итоге получают вот это...
Иванов Иван Иванович 1980 М Сволоч а мне бы в таблицу |
|||
5
IamAlexy
28.03.12
✎
12:49
|
(1) да
сколько между запятыми слов столько и колонок - то есть 6 |
|||
6
le_
28.03.12
✎
12:50
|
||||
7
IamAlexy
28.03.12
✎
12:50
|
(2) да ппц.. все утро курю эту статью.. ну нихрена не понимаю..
яж блин тупой 1Сник.. а в статье намеки которые мне ни разу не понятны |
|||
8
Ёпрст
28.03.12
✎
12:51
|
тупо substring + charindex
|
|||
9
Fram
28.03.12
✎
12:51
|
(0) Из 1С можно пачками по 100000 записей обработать. Потом с помощью bulk insert обратно загрузить
|
|||
10
Джинн
28.03.12
✎
12:52
|
(4) Ну дык INSERT INTO
|
|||
11
Kom-off
28.03.12
✎
12:52
|
(7) Попробуй покури здесь: http://www.sql-ex.ru/help/select10.php#string_fun
|
|||
12
IamAlexy
28.03.12
✎
12:55
|
(9) весь прикол что эти данные потом надо в 1с дергать.. из внешнего источника.. хотелось бы их разово на SQL обработать и 1Ску не напрягать разбором строки...
|
|||
13
IamAlexy
28.03.12
✎
12:57
|
(8) вот я вот нифига не понял из того что ты сказал
|
|||
14
Ёпрст
28.03.12
✎
13:00
|
(13) те же пример в (2) есть
тупо находишь первую запятую через чариндекс, далее часть строки берешь через субстринг - это значение инсертишь в первую колонку, далее через стуфф, заменяешь это значение в исходной строке на пусто и повторяешь всё тоже самое для второй..N колонок.. Усё |
|||
15
Vakhrin
28.03.12
✎
13:08
|
Не проверял, но как-то так:
CREATE FUNCTION dbo.f_Part(@String varchar(8000), @Delimiter char(1), Number int) returns @Part varchar(8000) as begin declare ind int declare @poz int declare str varchar(8000) set ind = 0 set @poz = 1 set str = @String while ind != Number and @poz != 0 begin set ind = ind + 1 set @poz = charindex(@Delimiter, str) if @poz = 0 set @Part = str else begin set @Part = left(str, @poz - 1) set str = substring(str, @poz + 1) end end return end |
|||
16
le_
28.03.12
✎
13:09
|
(15) Прикольно собачки обработались )
|
|||
17
mikecool
28.03.12
✎
13:09
|
выгрузить в текст
загрузить из текста, указав разделители )) |
|||
18
Vakhrin
28.03.12
✎
13:09
|
гы... не все отобразилось, как в коде было...
там где отображение болдом - эт впереди стоит |
|||
19
IamAlexy
28.03.12
✎
13:13
|
блин.. гуглить и я умею.. только все примеры заканчиваются на результате:
Иванов Иван Иванович 1980 М Сволоч |
|||
20
Mikeware
28.03.12
✎
13:17
|
(0) базу данных по миздюкам собираешь? :-)
|
|||
21
IamAlexy
28.03.12
✎
13:22
|
(20) да
типа тово |
|||
22
Mikeware
28.03.12
✎
13:23
|
(21) надеюсь, я все-таки буду сволочью...
|
|||
23
mikecool
28.03.12
✎
13:23
|
(19) (17) не работает?
|
|||
24
le_
28.03.12
✎
13:24
|
(19) pivot (unpivot) можно использовать...
|
|||
25
Fram
28.03.12
✎
13:38
|
(12) так я тебе единоразово предлагаю обработать. ты же так в (0) задачу поставить. bulk insert очень быстро вставляет большие объемы данных из текстового файла
|
|||
26
Fram
28.03.12
✎
13:38
|
поставил
|
|||
27
IamAlexy
28.03.12
✎
13:40
|
(25) не очень верится что задача одноразовая...
|
|||
28
Капитан Смоллет
28.03.12
✎
13:45
|
//объявление переменных
DECLARE surname, @name, @midname, @sex, @fucker VARCHAR(30); DECLARE @parser_text TEXT; DECLARE @position INTEGER; SET @parser_text="Иванов,Иван,Иванович,м,сволочь"; //находим первую запятую SET @position = CHARINDEX(',', @parser_text); //выделяем фамилию SET surname = LEFT(@remainder_text, @position-1); SET @parser_text = RIGHT(@parser_text, @position+1); //аналогично находим имя, отчество и тд //запросом INSERT вставляем полученные значения куда надо |
|||
29
Fram
28.03.12
✎
13:48
|
(28) через текстовый файл и bulk insert быстрее
|
|||
30
IamAlexy
28.03.12
✎
14:20
|
хорошо, а если подойти по 1Совски, то есть
1. добавить нужное количество колонок к таблице 2. перебрать строки с незаполненными колонками и соответственно дозаполнить их? |
|||
31
rs_trade
28.03.12
✎
14:33
|
Держи
CREATE TABLE dbo.Table1 ( Name VARCHAR(30), [Values] VARCHAR(128) ) GO INSERT INTO dbo.Table1 VALUES ('1', 'Иванов, Иван, Иванович, 1980, М, Сволочь') INSERT INTO dbo.Table1 VALUES ('2', 'Петров, Сидор, Петрович, 1986, М, Недалекий') GO SELECT * FROM dbo.Table1; GO WITH L0 AS(SELECT 1 AS c UNION ALL SELECT 1), L1 AS(SELECT 1 AS c FROM L0 AS A, L0 AS B), L2 AS(SELECT 1 AS c FROM L1 AS A, L1 AS B), L3 AS(SELECT 1 AS c FROM L2 AS A, L2 AS B), Numbers AS(SELECT ROW_NUMBER() OVER(ORDER BY c) AS n FROM L3) SELECT Name, [1] AS Column1, [2] AS Column2, [3] AS Column3, [4] AS Column4, [5] AS Column5, [6] AS Column6 FROM (SELECT Name, ROW_NUMBER() OVER (PARTITION BY Name ORDER BY nums.n) AS PositionInList, LTRIM(RTRIM(SUBSTRING(valueTable.[Values], nums.n, charindex(N',', valueTable.[Values] + N',', nums.n) - nums.n))) AS [Value] FROM Numbers AS nums INNER JOIN dbo.Table1 AS valueTable ON nums.n <= CONVERT(int, LEN(valueTable.[Values])) AND SUBSTRING(N',' + valueTable.[Values], n, 1) = N',') AS SourceTable PIVOT ( MAX([VALUE]) FOR PositionInList IN ([1], [2], [3], [4], [5], [6]) ) AS Table2 GO DROP TABLE dbo.Table1 |
|||
32
Ёпрст
28.03.12
✎
14:46
|
(31) погодь, ща скажет , что в 2000 не работает
:) |
|||
33
IamAlexy
28.03.12
✎
14:47
|
(31) огромное человеческое спасибо
это именно то что нужно :) (32) 2008ой - все пашет :) |
|||
34
rs_trade
28.03.12
✎
14:48
|
(31) здесь нужен только запрос начинающийся с WITH
L0 AS(SELECT 1 AS c UNION ALL SELECT 1), вместо INNER JOIN dbo.Table1 подставь имя своей таблицы. ну и имена колонок соответственно. |
|||
35
Длинный Клиент
28.03.12
✎
14:50
|
(0) Задов, ты ?
|
|||
36
Ёпрст
28.03.12
✎
14:57
|
с пивотом конечно красиво, вот только у автора нема колонки с циферками еще..
|
|||
37
ковер
28.03.12
✎
14:58
|
(34) можешь мне помочь?
как запросом в MSSQL сделать такое есть таблица 02.01.2012 1 07.01.2012 6 22.01.2012 7 25.01.2012 8 нужно получить 01.01.2012 1 02.01.2012 1 03.01.2012 1 04.01.2012 1 05.01.2012 1 06.01.2012 1 07.01.2012 6 08.01.2012 6 09.01.2012 6 ... 22.01.2012 7 .... 25.01.2012 8 ... 31.01.2012 8 |
|||
38
rs_trade
28.03.12
✎
15:01
|
(36) если нет колонки с каким либо id, заменить в запросе колонку Name на Values
|
|||
39
IamAlexy
28.03.12
✎
15:02
|
(35) нет, не я...
|
|||
40
rs_trade
28.03.12
✎
15:02
|
(37) это вообще просто джойн со списком дат на каждый день
|
|||
41
ковер
28.03.12
✎
15:05
|
(40) черкани запрос если не трудно
|
|||
42
Длинный Клиент
28.03.12
✎
15:16
|
(39) Просто содержимое БД подозрительное, особенно в поле характеристики фио !
|
|||
43
Ёпрст
28.03.12
✎
15:21
|
(41)
declare t table (date datetime,kol int) insert into t values('20120102',1) insert into t values('20120107',6) insert into t values('20120122',7) insert into t values('20120125',8) select * from t select a.Dat ,Max(t.kol) from (select dateadd(day,(a.number+b.number*256),'20120101') as Dat from master..spt_values a, master..spt_values b where a.type='P' and b.type='P' and b.number<=datediff(day,'20120101','20120131')/256 and a.number<=(datediff(day,'20120101','20120131')-b.number*256)) a left join t t on t.date<=a.Dat group by a.Dat order by a.Dat |
|||
44
Ёпрст
28.03.12
✎
15:28
|
точнее так
declare t table (date datetime,kol int) insert into t values('20120102',1) insert into t values('20120107',6) insert into t values('20120122',7) insert into t values('20120125',8) select * from t select a.Dat ,min(t.kol) from (select dateadd(day,(a.number+b.number*256),'20120101') as Dat from master..spt_values a, master..spt_values b where a.type='P' and b.type='P' and b.number<=datediff(day,'20120101','20120131')/256 and a.number<=(datediff(day,'20120101','20120131')-b.number*256)) a left join t t on t.date>=a.Dat --or group by a.Dat order by a.Dat |
|||
45
ковер
28.03.12
✎
15:36
|
(44) о спасибо, монстр :)
|
|||
46
rs_trade
28.03.12
✎
15:55
|
для удобночитаемости можно табличку за датами в CTE вынести
declare t table (date datetime, kol int) insert into t values('20120102',1) insert into t values('20120107',6) insert into t values('20120122',7) insert into t values('20120125',8) select * from t; with table_date as ( select dateadd(day,(a.number+b.number*256),'20120101') as Dat from master..spt_values a, master..spt_values b where a.type='P' and b.type='P' and b.number<=datediff(day,'20120101','20120131')/256 and a.number<=(datediff(day,'20120101','20120131')-b.number*256) ) select a.Dat ,min(t.kol) from table_date a left join t t on t.date>=a.Dat --or group by a.Dat order by a.Dat; |
|||
47
IamAlexy
28.03.12
✎
15:57
|
(42) я знал что конспируолухи поведутся :)
|
|||
48
Ёпрст
28.03.12
✎
15:58
|
блин.. везде где обращение к t - воткнуть амперсанд @ который съелся форумом
|
|||
49
IamAlexy
28.03.12
✎
16:05
|
так.
вроде все получается, теперь вопрос чисто технический - что лучше сделать - регламентным заданием конвертировать одну таблицу в другую - чтобы физика лежала в бд или же сделать хранимую процедуру и к ней обращаться? с условием того что будет осуществлятся поиск по Фамилии например из 1С.. |
|||
50
toypaul
гуру
28.03.12
✎
16:10
|
зачем скрипт, когда можно типовыми средствами переноса сделать
|
|||
51
rs_trade
28.03.12
✎
16:13
|
(49) сделай вьюху и прицепи ее с помощью внешних источников к 1С
|
|||
52
rs_trade
28.03.12
✎
16:15
|
во вьюхе будут всегда актуальные данные разложенные по столбцам
|
|||
53
IamAlexy
28.03.12
✎
16:16
|
(51) что такое вьюха?
хранимая процедура или что? |
|||
54
rs_trade
28.03.12
✎
16:18
|
||||
55
rs_trade
28.03.12
✎
16:19
|
IF object_id(N'MyView', 'V') IS NOT NULL
DROP VIEW MyView GO CREATE VIEW MyView AS WITH L0 AS(SELECT 1 AS c UNION ALL SELECT 1), L1 AS(SELECT 1 AS c FROM L0 AS A, L0 AS B), L2 AS(SELECT 1 AS c FROM L1 AS A, L1 AS B), L3 AS(SELECT 1 AS c FROM L2 AS A, L2 AS B), Numbers AS(SELECT ROW_NUMBER() OVER(ORDER BY c) AS n FROM L3) SELECT Name, [1] AS Column1, [2] AS Column2, [3] AS Column3, [4] AS Column4, [5] AS Column5, [6] AS Column6 FROM (SELECT Name, ROW_NUMBER() OVER (PARTITION BY Name ORDER BY nums.n) AS PositionInList, LTRIM(RTRIM(SUBSTRING(valueTable.[Values], nums.n, charindex(N',', valueTable.[Values] + N',', nums.n) - nums.n))) AS [Value] FROM Numbers AS nums INNER JOIN dbo.Table1 AS valueTable ON nums.n <= CONVERT(int, LEN(valueTable.[Values])) AND SUBSTRING(N',' + valueTable.[Values], n, 1) = N',') AS SourceTable PIVOT ( MAX([VALUE]) FOR PositionInList IN ([1], [2], [3], [4], [5], [6]) ) AS Table2 |
|||
56
rs_trade
28.03.12
✎
16:20
|
в базе появиться виртуальная табличка MyView с нужным тебе результатом.
|
|||
57
IamAlexy
28.03.12
✎
16:20
|
(54) спс.. разобрался :)
|
|||
58
rs_trade
28.03.12
✎
16:33
|
индексы еще на вьюху надо будет наложить. вообще интересно производительность данного способа узнать. на табличке в пару лямов записей.
|
|||
59
IamAlexy
28.03.12
✎
16:41
|
(58) вот об чем и речь...
записей то - доФУЯ |
|||
60
IamAlexy
28.03.12
✎
16:42
|
ладно, щас вьюху сваяю..
посмотрим - что скажет нагрузочное тестирование... |
|||
61
rs_trade
28.03.12
✎
16:56
|
не прокатят наверное вьюхи. их индексировать не получиться, ибо слишком сложный исходный запрос. можно создать не индексированную въюху, но как скуль будет в ней искать хз
|
|||
62
IamAlexy
28.03.12
✎
17:37
|
(61) потестю на паре миллионов записей...
если будет тупить - то придется выпрашивать схему обновления физической таблицы данными из исходной |
|||
63
Длинный Клиент
28.03.12
✎
18:05
|
(62) Что же ты-таки мутишь, то ли в свежую 1С базу перегоняешь данные ПФР, потом отдашь продавать на Савеле, то ли начал работать с базой Мавродия.
|
|||
64
rs_trade
28.03.12
✎
18:58
|
вот еще вариант. функция.
-- ============================================= -- Author: Reza Rad -- Version: 1.0 -- Create date: 21/02/2012 -- Description: To Split a Delimited field by a Delimiter -- ============================================= CREATE FUNCTION [dbo].[SplitFieldByDelimiter] ( @fieldname varchar(max) ,@delimiter varchar(max) ,@delimiter_count int ) RETURNS varchar(max) AS BEGIN -- variable declaration declare @first_index varchar(max) ,@next_index varchar(max) ,@sql_statement varchar(max) ,@term_statement varchar(max) ,@length varchar(max) ,@iterator int -- initialization set @next_index=-1 set @iterator=1 set @sql_statement=' ' -- code while(@iterator<=@delimiter_count) begin set @first_index=@next_index+'+1' set @next_index='CHARINDEX('''+@delimiter+''','+@fieldname+','+@first_index+')' if (@iterator=@delimiter_count) begin set @next_index='LEN('+@fieldname+')+1' end set @length=@next_index+'-('+@first_index+')' set @term_statement='SubString('+@fieldname+','+@first_index+','+@length+')' set @term_statement='case when '+@next_index+'>0 then '+@term_statement+' else ''nothing'' end as Column'+CONVERT(varchar(max),@iterator) if (@iterator=1) begin set @sql_statement=@term_statement end else begin set @sql_statement=@sql_statement+', '+@term_statement end set @iterator=@iterator+1 end -- Return the result of the function RETURN @sql_statement END |
|||
65
rs_trade
28.03.12
✎
19:00
|
ее использование
declare @sql varchar(max) set @sql='select '+dbo.SplitFieldByDelimiter('ИмяКолонкиГдеТекстЛежит',',',6) +' from [dbo].[Table1]' exec (@sql) |
|||
66
rs_trade
28.03.12
✎
19:01
|
создание индексированной вьюхи
declare @sql varchar(max) set @sql='create view myView WITH SCHEMABINDING as select '+dbo.SplitFieldByDelimiter('ИмяКолонкиГдеТекстЛежит',',',6) +' from [dbo].[Table1]' exec (@sql) |
|||
67
rs_trade
28.03.12
✎
19:02
|
создание индекса для вьюхи
CREATE UNIQUE CLUSTERED INDEX IDX_V1 ON dbo.myView (ИмяКолонкиПоКоторойИскатьБудешь); |
|||
68
rs_trade
28.03.12
✎
19:02
|
в этом варианте индексов скока надо на вьюху можно наложить
|
|||
69
IamAlexy
28.03.12
✎
19:03
|
спс.... будем тестить..
завтра заполню базу лямом записей.. посмотрим как сервак прогнется |
|||
70
rs_trade
29.03.12
✎
18:27
|
ну хде результаты? интересно же.
|
|||
71
IamAlexy
30.03.12
✎
16:04
|
(70) методом научного тыка привожу входящие данные средствами скуля в удобчитаемый вариант
|
|||
72
IamAlexy
01.04.12
✎
15:07
|
В процессе нагрузочного тестирования возник вопрос: как работает представление (вьюшка)?
вот допустим у меня есть физическая таблица с колонкой в которой строка "Иванов дурак" Вьюшка соответственно показывает 2 колонки. В первой "Иванов" во второй "Дурак" соответственно мне нужно сделать запрос и выбрать всех дураков из вьюшки. вопрос: как сработает вся эта схема? сначала вьюшка фиганет и обработает всю таблицу физическую а затем по этой вьюшке сработает запрос? так ведь? то есть если физическая таблица например содержит миллионы записей то любой запрос к вьюшке будет приводить к пересчету всех этих миллионов записей? |
|||
73
IamAlexy
01.04.12
✎
15:08
|
+(72) то есть использование этих самых вьюшег для больших, постоянно дополняемых таблиц неоправданно?
|
|||
74
rs_trade
02.04.12
✎
08:23
|
не думаю что скуль настолько туп, что бы пересчитывать миллионы записей. как то это дело оптимизируется наверняка.
|
|||
75
rs_trade
02.04.12
✎
11:28
|
не хранятся в базе не индексированные представления. индексированные представления вычисляются и хранятся в базе.
|
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |