Related
with the below loop script, I am creating tables for every period. What I need is that I would like to union all these multiple tables into one single table within the same script. Can anyone help me do that?
DECLARE #Interval_List as TABLE (index_1 int, Interval VARCHAR(50), Interval_2 VARCHAR(50), From_date date, To_date date)
INSERT INTO #Interval_List VALUES (1, '2021_Q3', '2021 Q3', '2021-07-01', '2021-09-30')
INSERT INTO #Interval_List VALUES (2, '2021_Q4', '2021 Q4', '2021-10-01', '2021-12-31')
INSERT INTO #Interval_List VALUES (3, '2021_H2', '2021 H2', '2021-07-01', '2021-12-31')
INSERT INTO #Interval_List VALUES (4, '2021', '2021', '2021-07-01', '2021-12-31')
DECLARE #StartDate AS DATE
DECLARE #EndDate AS DATE
DECLARE #CurrentDate AS DATE
DECLARE #index_first int
declare #index_last int
declare #interval VARCHAR(50)
declare #interval_2 VARCHAR(50)
declare #issue_table nvarchar(max)
declare #service_table nvarchar(max)
SELECT #index_first = min(index_1), #index_last = max(index_1) FROM #Interval_List
SET #CurrentDate = #StartDate
SET #issue_table = 'dbo.table1'
SET #service_table = 'dbo.table2'
WHILE (#index_first <= #index_last)
BEGIN
SELECT #StartDate = From_date, #EndDate = To_date, #interval = Interval, #interval_2 = Interval_2 FROM #Interval_List where index_1 = #index_first
IF OBJECT_ID(#issue_table) IS NULL
BEGIN
RAISERROR('Bad object!', 11, 1);
RETURN;
END
declare #query nvarchar(max);
set #query =
N'
SELECT
A.SERVICE,
A.Service_Group,
A.Portfolio,
Interval,
SUM(Metric_1_Dividend_C_New) AS Metric_1_Dividend_C_New
'
+ N'into dbo.METRIC_1_' + #interval
+
N'
FROM
(
SELECT
ISSUE_CREATION_DATE,
ISSUE_ID,
SERVICE,
SERVICE_GROUP,
PORTFOLIO,
#Interval_2 as Interval,
AVG(Metric_No_1_Dividend) AS Metric_1_Dividend_C_New
'
+ N' from ' + #issue_table +
N' where PROJECT IS NOT NULL
AND cast(FORMAT(ISSUE_CREATION_DATE, ''yyyyMMdd'') as varchar(30)) >= cast(FORMAT(#StartDate, ''yyyyMMdd'') as varchar(30))
AND cast(FORMAT(ISSUE_CREATION_DATE, ''yyyyMMdd'') as varchar(30)) <= cast(FORMAT(#EndDate, ''yyyyMMdd'') as varchar(30))
GROUP BY ISSUE_CREATION_DATE, ISSUE_ID,SERVICE,SERVICE_GROUP,PORTFOLIO
) A
GROUP BY SERVICE,Service_Group,Portfolio,Interval
'
exec sys.sp_executesql #query,
N'#StartDate date, #EndDate date, #Interval_2 VARCHAR(50)',
#StartDate, #EndDate, #Interval_2;
SET #index_first = #index_first + 1;
END
;
Before you continue, please make sure that you read about table partitioning and creating a view for your unions, because, intuitively the problem you describe sounds like these. If neither partitioning, nor views are good for you, then read the sections below:
How can I get tables by name
SELECT [name]
FROM sys.tables
WHERE [name] LIKE '%somepattern%'
How to generate a command:
SELECT CONCAT('INSERT INTO ', [name], '(col1, col2, col3) values(', value1, ', ', value2, ', ', value3, ')')
FROM sys.tables
WHERE [name] LIKE '%somepattern%'
How to concatenate rows
You can use STRING_AGG(yourstring, 'separator'), like:
SELECT STRING_AGG(CONCAT('INSERT INTO ', [name], '(col1, col2, col3) values(', value1, ', ', value2, ', ', value3, ')'), ' UNION ')
FROM sys.tables
WHERE [name] LIKE '%somepattern%'
I am trying to write a procedure that will check all rows in my table and if itemID = 'CC100' then I need to insert a new row into the table. I have generated this script, but I am getting an error when I try to execute it
Msg 156, Level 15, State 1, Line 33
Incorrect syntax near the keyword 'Select'.
How should this be altered to become valid t-sql, or what is a more appropriate way to accomplish my desired result? Sample DDL is below:
--Create Holding Table
Declare Table #Items
(
itemID varchar(20)
,itemName varchar(100)
,qty int
,storeID int
)
--Insert Some Sample Data
Insert Into #Items (itemID, itemName, qty, storeID) Values
('CZ100', 'Coke Zero', 4, 123), ('CZ100', 'Coke Zero', 3, 201)
,('CZ200', 'Cherry Coke Zero', 4, 311), ('CC100', 'Coca-Cola', 6, 400)
,('CC100', 'Coca-COla', 8, 500)
--Select data that needs to be split into secondary table
Select storeID, Qty Into #NeedExtra from #Items WHERE itemID = 'CC100'
--Declare variables
Declare #storeID int, #Qty int
--Create Cursor
DECLARE cursor1 CURSOR FOR
--Select statement to insert into variables
SELECT
storeID, qty
FROM #NeedExtra
OPEN cursor1
--Iterate cursor
FETCH NEXT FROM cursor1 INTO #storeID, #qty
--Continue as long as cursor is not empty
WHILE ##FETCH_STATUS = 0
BEGIN
--Insert Values
Insert Into #Items (itemID, itemName, qty, storeID) Values
Select #storeID, 'CC200', 'Coca-Cola Syrup', #Qty, #storeID FROM #NeedExtra
--Grab next item from temp table
FETCH NEXT FROM cursor1 INTO #storeID, #qty
END
--Close cursor
CLOSE cursor1
--Deallocate cursor
DEALLOCATE cursor1
--Select statements
Select * FROM #NeedExtra
SELECT * FROM #Items
First, your insert query in while loop is not correct.
Insert Into #Items (itemID, itemName, qty, storeID) Values
Select #storeID, 'CC200', 'Coca-Cola Syrup', #Qty, #storeID FROM #NeedExtra
There isn't a syntax like Insert into ... values select, and number of columns inserted is not matched.
And if it's correct the item with value #storeID, 'CC200', 'Coca-Cola Syrup', #Qty, #storeID will be duplicate many times equals count of #NeedExtra.
The correct query would be
Insert Into #Items (itemID, itemName, qty, storeID) Values
('CC200', 'Coca-Cola Syrup', #Qty, #storeID)
Second, you should avoid using CURSOR and change your CURSOR loop by this insert query.
Insert Into #Items (itemID, itemName, qty, storeID)
Select 'CC200', 'Coca-Cola Syrup', t.Qty, t.storeID
FROM #Items t WHERE t.itemID = 'CC100'
The right syntax of INSERT INTO SELECT doesn't use values keyword. So just remove Values keyword from line 33 of your procedure.
I altered your code a follows, should work now.
--Create Holding Table
Declare #Items As Table
(
itemID varchar(20)
,itemName varchar(100)
,qty int
,storeID int
)
--Insert Some Sample Data
Insert Into #Items (itemID, itemName, qty, storeID) Values
('CZ100', 'Coke Zero', 4, 123), ('CZ100', 'Coke Zero', 3, 201)
,('CZ200', 'Cherry Coke Zero', 4, 311), ('CC100', 'Coca-Cola', 6, 400)
,('CC100', 'Coca-COla', 8, 500)
--Select data that needs to be split into secondary table
Select storeID, Qty Into #NeedExtra from #Items WHERE itemID = 'CC100'
--Declare variables
Declare #storeID int, #Qty int
--Create Cursor
DECLARE cursor1 CURSOR FOR
--Select statement to insert into variables
SELECT
storeID, qty
FROM #NeedExtra
OPEN cursor1
--Iterate cursor
FETCH NEXT FROM cursor1 INTO #storeID, #qty
--Continue as long as cursor is not empty
WHILE ##FETCH_STATUS = 0
BEGIN
--Insert Values
Insert Into #Items (itemID, itemName, qty, storeID)
Select 'CC200', 'Coca-Cola Syrup', #Qty, #storeID FROM #NeedExtra
--Grab next item from temp table
FETCH NEXT FROM cursor1 INTO #storeID, #qty
END
--Close cursor
CLOSE cursor1
--Deallocate cursor
DEALLOCATE cursor1
--Select statements
Select * FROM #NeedExtra
SELECT * FROM #Items
I have a sql table that has the following
ID StartDate EndDate
10 2015-12-01 2016-05-31
15 2016-01-05 2016-07-04
20 2016-02-10 2016-08-09
I need to break down the months like so...
ID StartDate EndDate
10 2015-12-01 2015-12-31
10 2016-01-01 2016-01-31
10 2016-02-01 2016-02-29
10 2016-03-01 2016-03-31
10 2016-04-01 2016-04-30
10 2016-05-01 2016-05-31
15 2016-01-05 2016-02-04
15 2016-02-05 2016-03-04
15 2016-03-05 2016-04-04
15 2016-04-05 2016-05-04
15 2016-05-05 2016-06-04
15 2016-06-05 2016-07-04
etc
I'm new to SQL so an example would be very helpful
Calendar
recommended if you have persistent Calendar/DateRanges table
declare #datebegin date = '20140101'
;with cteCalendar as
(
select
c.period_start,
dateadd(dd, -1, dateadd(mm, 1, c.period_start)) as period_end
from
(
select top 100
dateadd(mm, row_number() over(order by sc.object_id)-1, #datebegin) as period_start
from sys.columns sc
order by period_start
) c
),
cteData as
(
select cast(10 as int) as id, cast('20151201' as date) as StartDate, cast('20160531' as date) as EndDate
union all
select 15, '20160105', '20160704'
union all
select 25, '20160210', '20160809'
),
cteDataEx as
(
select d.id, d.StartDate, d.EndDate, datepart(dd, d.StartDate)-1 as DateOffset
from cteData d
)
select
d.id,
dateadd(dd, d.DateOffset, c.period_start) as StartDate,
dateadd(dd, d.DateOffset, c.period_end) as EndDate
from cteDataEx d
inner join cteCalendar c on c.period_start <= d.EndDate and c.period_end >= d.StartDate
where dateadd(dd, d.DateOffset, c.period_end) <= d.EndDate
order by id, StartDate
Actually I did not notice at the beginning that periods may start and end not at 1st day of month, so had to append some calculations after completion of the whole script. Later I realized that <= >= date filter produces unnecessary last row which overflows original date range high bound. So had to append final filter and after that modification don't like this approach totally )) May be some enhancements can be applied but I'm not interested in. Lots of ways to accomplish this task. Additional information about nature and purpose of periods given may alter relevance and applicability of different approaches
Recursion
no extra data required but recursion can be slow if date ranges can be wide enough.
;with cteData as
(
select cast(10 as int) as id, cast('20151201' as date) as StartDate, cast('20160531' as date) as EndDate
union all
select 15, '20160105', '20160704'
union all
select 25, '20160210', '20160809'
),
ctePeriods as
(
select
d.id,
d.StartDate,
dateadd(dd, -1, dateadd(mm, 1, d.StartDate)) as EndDate,
d.EndDate as _EndDate
from cteData d
union all
select
p.id,
dateadd(mm, 1, p.StartDate),
dateadd(dd, -1, dateadd(mm, 2, p.StartDate)),
p._EndDate
from ctePeriods p
where p.EndDate < p._EndDate
)
select p.id, p.StartDate, p.EndDate
from ctePeriods p
order by id, startdate
this code generate the rage of months, inclute leap year, but I don't undestand your need so explain better
create table #dia_meses
(mes int,
messtr varchar(2),
dia_final varchar(2))
insert into #dia_meses values(1,'01','31')
insert into #dia_meses values(2,'02','29')
insert into #dia_meses values(3,'03','31')
insert into #dia_meses values(4,'04','30')
insert into #dia_meses values(5,'05','31')
insert into #dia_meses values(6,'06','30')
insert into #dia_meses values(7,'07','31')
insert into #dia_meses values(8,'08','31')
insert into #dia_meses values(9,'09','30')
insert into #dia_meses values(10,'10','31')
insert into #dia_meses values(11,'11','30')
insert into #dia_meses values(12,'12','31')
declare #year varchar(4)
declare #contador int
set #year =convert(varchar,DATEPART(YEAR,GETDATE()))
set #contador =convert(varchar,DATEPART(month,GETDATE()))
declare #dataIni datetime
declare #datafim datetime
set #dataIni=(select #year+'-'+messtr+'-01' from #dia_meses where mes=#contador)
--pulo do gato ano bissexto
if(#contador=2)
begin
if(select ISDATE(#year+'-'+messtr+'-'+dia_final) from #dia_meses where mes=#contador)=0
begin
set #datafim=(select #year+'-'+messtr+'-28' from #dia_meses where mes=#contador)
end
else--ano bissexto
begin
set #datafim=(select #year+'-'+messtr+'-'+dia_final from #dia_meses where mes=#contador)
end
end
else
begin
set #datafim=(select #year+'-'+messtr+'-'+dia_final from #dia_meses where mes=#contador)
end
print #dataIni
print #dataFim
This will work on SQL Server 2012 and up; the EOMONTH function does not exist on earlier versions.
DECLARE #table TABLE (ID INT, StartDate DATE, EndDate DATE)
DECLARE #outtable TABLE (ID INT, StartDate DATE, EndDate DATE)
DECLARE #ID INT
DECLARE #StartDate DATE
DECLARE #Date1 DATE
DECLARE #Date2 DATE
DECLARE #EndDate DATE
INSERT INTO #table VALUES
(10,'2015-12-01','2016-05-31')
,(15,'2016-01-05','2016-07-04')
,(20,'2016-02-10','2016-08-09')
DECLARE tablecursor CURSOR FOR
SELECT * FROM #table
OPEN tablecursor
FETCH NEXT FROM tablecursor INTO #ID, #StartDate, #EndDate
WHILE ##FETCH_STATUS = 0
BEGIN
SET #Date1 = #StartDate
SET #Date2 = EOMONTH(#Date1)
WHILE #Date1 < #EndDate
BEGIN
PRINT CONVERT(VARCHAR,#ID) + ' ' + CONVERT(VARCHAR,#Date1) + ' ' + CONVERT(VARCHAR,#Date2)
INSERT INTO #outtable
SELECT #ID, #Date1, #Date2
SET #Date1 = DATEADD(DAY,1,#Date2)
SET #Date2 = EOMONTH(#Date1)
IF #Date2 > #EndDate
BEGIN
SET #Date2 = #EndDate
END
END
FETCH NEXT FROM tablecursor INTO #ID, #StartDate, #EndDate
END
SELECT * FROM #outtable
CLOSE tablecursor
DEALLOCATE tablecursor
Is there an easy way of determining the most frequently occuring word in a column/field using T-SQL or VBA?
I am working on a fuzzy matching system for two given recordsets and would like to produce a matching string where the most frequently occuring words are removed. As the data is from a customer relations management database terms like "limited", "ltd", "plc" and "CORPORATION" would be removed.
Written for sql-server 2005+
Function to split:
create function f_split
(
#a varchar(max),
#delimiter varchar(20)
)
RETURNS #t TABLE(substr varchar(200))
as
begin
set #a = #a + #delimiter
;with a as
(
select cast(1 as bigint) f1, charindex(#delimiter, #a) f2
where len(#a) > 0
union all
select f2 + (len(#delimiter)) + 1, charindex(#delimiter, #a, f2+1)
from a
where f2 > 0
)
insert #t
select substring(#a, f1, f2 - f1) from a
where f1 < f2
return
end
go
Query:
--testdata
declare #table table(name varchar(50))
insert #table values('bla bla bla ltd')
insert #table values('bla plc ltd')
insert #table values('more text CORPORATION')
declare #matchlist table(name varchar(50), replacement varchar(50))
insert #matchlist values('ltd', 'limited')
insert #matchlist values('plc', 'limited')
insert #matchlist values('CORPORATION', 'limited')
--query
select coalesce(m.replacement, a.substr) name, count(*) count from #table p
cross apply
(
select substr from
dbo.f_split(p.name, ' ')
) a
left join
#matchlist m
on a.substr = m.name
group by coalesce(m.replacement, a.substr)
order by 2 desc
Result:
name count
---- -----
bla 4
limited 4
more 1
text 1
Hope this will be useful to you.
create table sometable
( id integer not null primary key identity
, mYWords text not null
);
insert into sometable (mYWords)
values ('a word that appears maximum number of times in a column')
insert into sometable (mYWords)
values ('Is it possible to get words from text columns in a sql server database')
insert into sometable (mYWords)
values ('This could solve my problem if reffered column contain only single word')
insert into sometable (mYWords)
values ('that''s going to require that you split out every word in the column individually')
insert into sometable (mYWords)
values ('the query will definitely not be easy to write')
insert into sometable (mYWords)
values ('Please read the sticky at the top of the board')
insert into sometable (mYWords)
values ('The physical order of data in a database has no meaning')
GO
CREATE TABLE WordList (
Word varchar(256)
, WordId int IDENTITY(1,1)
, Add_Dt datetime DEFAULT (GetDate()))
GO
CREATE UNIQUE INDEX UnqueWords_PK ON WordList(Word)
GO
CREATE PROC isp_INS_WORD_LIST
AS
BEGIN
SET NOCOUNT ON
DECLARE #Words INT, #Pos INT, #x Int, #str varchar(256)
, #word varchar(256), #start int, #end int, #exitstart int
SELECT #Words = 0, #Pos = 1, #x = -1, #Word = '', #start = 1
DECLARE Cur1 CURSOR FOR SELECT mYWords FROM sometable
OPEN Cur1
FETCH NEXT FROM Cur1 INTO #str
WHILE ##FETCH_STATUS = 0
BEGIN
WHILE (#x <> 0)
BEGIN
SET #x = CHARINDEX(' ', #str, #Pos)
IF #x <> 0
BEGIN
SET #end = #x - #start
SET #word = SUBSTRING(#str,#start,#end)
IF NOT EXISTS (SELECT * FROM WordList WHERE Word = #Word)
INSERT INTO WordList(Word) SELECT #word
-- SELECT #Word, ##ROWCOUNT,##ERROR
-- SELECT #x, #Word, #start, #end, #str
SET #exitstart = #start + #end + 1
SET #Pos = #x + 1
SET #start = #x + 1
SET #Words = #Words + 1
END
IF #x = 0
BEGIN
SET #word = SUBSTRING(#str,#exitstart,LEN(#str)-#exitstart+1)
IF NOT EXISTS (SELECT * FROM WordList WHERE Word = #Word)
INSERT INTO WordList(Word) SELECT #word
-- SELECT #Word, ##ROWCOUNT,##ERROR
-- SELECT #x, #Word, #exitstart, LEN(#str)-#exitstart, #str
END
END
FETCH NEXT FROM Cur1 INTO #str
SELECT #Words = 0, #Pos = 1, #x = -1, #Word = '', #start = 1
END
CLOSE Cur1
DEALLOCATE Cur1
SET NOCOUNT OFF
RETURN #Words
END
GO
EXEC isp_INS_WORD_LIST
GO
SELECT * FROM WordList ORDER BY Word
GO
DROP PROC isp_INS_WORD_LIST
DROP TABLE WordList, sometable
GO
I have data in a table which looks like this (worth noting its not CSV seperated)
It needs to be split in to single chars
Data
abcde
want to convert it to this
Data
a
b
d
c
e
I have looked on the internet but have not found the answer
CREATE FUNCTION dbo.SplitLetters
(
#s NVARCHAR(MAX)
)
RETURNS #t TABLE
(
[order] INT,
[letter] NCHAR(1)
)
AS
BEGIN
DECLARE #i INT;
SET #i = 1;
WHILE #i <= LEN(#s)
BEGIN
INSERT #t SELECT #i, SUBSTRING(#s, #i, 1);
SET #i = #i + 1;
END
RETURN;
END
GO
SELECT [letter]
FROM dbo.SplitLetters(N'abcdefgh12345 6 7')
ORDER BY [order];
Previous post that solves the problem: TSQL UDF To Split String Every 8 Characters
Pass a value of 1 to #length.
declare #T table
(
ID int identity,
Data varchar(10)
)
insert into #T
select 'ABCDE' union
select '12345'
;with cte as
(
select ID,
left(Data, 1) as Data,
stuff(Data, 1, 1, '') as Rest
from #T
where len(Data) > 0
union all
select ID,
left(Rest, 1) as Data,
stuff(Rest, 1, 1, '') as Rest
from cte
where len(Rest) > 0
)
select ID,
Data
from cte
order by ID
You could join the table to a list of numbers, and use substring to split data column into rows:
declare #YourTable table (data varchar(50))
insert #YourTable
select 'abcde'
union all select 'fghe'
; with nrs as
(
select max(len(data)) as i
from #YourTable
union all
select i - 1
from nrs
where i > 1
)
select substring(yt.data, i, 1)
from nrs
join #YourTable yt
on nrs.i < len(yt.data)
option (maxrecursion 0)
declare #input varchar(max);
set #input = 'abcde'
declare #table TABLE (char varchar(1));
while (LEN(#input)> 0)
begin
insert into #table select substring(#input,1,1)
select #input = RIGHT(#input,Len(#input)-1)
end
select * from #table