Имя: Пароль:
IT
Админ
Гуру 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
не хранятся в базе не индексированные представления. индексированные представления вычисляются и хранятся в базе.
Выдавать глобальные идеи — это удовольствие; искать сволочные маленькие ошибки — вот настоящая работа. Фредерик Брукс-младший