It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
I have table with contract_code column, but in this column have same data, how can I change the same data to samedata_a, and samedata_b and etc.
For example:
Change this data
ASFRETERT
JDFJDSFJS
ASFRETERT
TO
ASFRETERT_a
JDFJDSFJS
ASFRETERT_b
You can perform this by applying a row_number() to the column. If you don't need the additional character to be an alpha character then it would be easier using the following:
The first version using CTE:
-- cte version
;with cte as
(
select col1, row_number() over(partition by col1 order by col1) rn
from yourtable
)
select
case when t1.cnt > 1
then c.col1 + '_'
+ cast(c.rn as varchar(10))
else c.col1
end yourColumn
from cte c
inner join
(
select count(*) cnt, col1
from yourtable
group by col1
) t1
on c.col1 = t1.col1;
The second version uses sub-queries
-- non-cte version
select case when t2.cnt > 1
then t1.col1 + '_'
+ cast(t1.rn as varchar(10))
else t1.col1
end yourColumn
from
(
select col1, row_number() over(partition by col1 order by col1) rn
from yourtable
) t1
inner join
(
select count(*) cnt, col1
from yourtable
group by col1
) t2
on t1.col1 = t2.col1
See SQL Fiddle with Demo. The two versions above add an integer to the end of the column but if you want to apply an alpha character, you should add a function to your database (Code for function from this question on StackOverflow):
CREATE FUNCTION dbo.fnColumnNameFromIndex(#i int)
RETURNS varchar(3)
AS
BEGIN
DECLARE #dividend int, #letters varchar(3), #modulo int
SET #dividend = #i
SET #letters = ''
WHILE #dividend > 0
BEGIN
SET #modulo = (#dividend - 1) % 26
SET #letters = CHAR(65 + #modulo) + #letters
SET #dividend = CONVERT(int, (#dividend - #modulo) / 26 )
END
RETURN #letters
END
If you create this function, then you can get the alpha character for each row. Your queries would then be:
The CTE version:
-- cte version
;with cte as
(
select col1, row_number() over(partition by col1 order by col1) rn
from yourtable
)
select
case when t1.cnt > 1
then c.col1 + '_'
+ cast(dbo.fnColumnNameFromIndex(c.rn) as varchar(10))
else c.col1
end yourColumn
from cte c
inner join
(
select count(*) cnt, col1
from yourtable
group by col1
) t1
on c.col1 = t1.col1;
The sub query version:
-- non-cte version
select case when t2.cnt > 1
then t1.col1 + '_'
+ cast(dbo.fnColumnNameFromIndex(t1.rn) as varchar(10))
else t1.col1
end yourColumn
from
(
select col1, row_number() over(partition by col1 order by col1) rn
from yourtable
) t1
inner join
(
select count(*) cnt, col1
from yourtable
group by col1
) t2
on t1.col1 = t2.col1
See SQL Fiddle with Demo
Related
If database d1 has tables T1,T2,T3,T4 all with the field "Date1".
What is the best way to get a count of all records across all tables with a date older than 3 days ago?
I know one could do unions, I assume there is no nifty syntax that would omit all tables [like a 'parent' object in C++].
Here best may mean more efficient, or just a pleasing syntax in T-SQL.
This is for SSMS 17.7. Microsoft SQL Server 2014 (SP2)
If you know the table names in advance, a simple query on union all will probably be the simplest way:
SELECT COUNT(*)
FROM
(
SELECT Date1
FROM T1
UNION ALL
SELECT Date1
FROM T2
SELECT Date1
FROM T3
SELECT Date1
FROM T4
) As t
WHERE Date1 <= DATEADD(DAY, -3, GETDATE())
If you don't know the table names in advance, you can use information_schema.columns to build the union query dynamically.
Well, you're interested in a parent object, that would be a view, then. You can reuse it for a variety of queries. Alternatively, add more columns if you need them:
CREATE VIEW parent AS
SELECT Date1 FROM t1 UNION ALL
SELECT Date1 FROM t2 UNION ALL
SELECT Date1 FROM t3 UNION ALL
SELECT Date1 FROM t4;
And now, that can be queried in the way you want
SELECT COUNT(*) FROM parent WHERE Date1 <= DATEADD(DAY, -3, GETDATE())
Without UNION?
Since a COUNT without a GROUP BY returns 1 value, why not use CROSS JOIN for once?
SELECT
t1.Cnt AS [T1],
t2.Cnt AS [T2],
t3.Cnt AS [T3],
t4.Cnt AS [T4],
(t1.Cnt + t2.Cnt + t3.Cnt + t4.Cnt) AS [T1234]
FROM
(SELECT COUNT(*) AS Cnt FROM T1 WHERE [Date1] < CAST(GetDate()-3 AS DATE)) AS t1
CROSS JOIN
(SELECT COUNT(*) AS Cnt FROM T2 WHERE [Date1] < CAST(GetDate()-3 AS DATE)) AS t2
CROSS JOIN
(SELECT COUNT(*) AS Cnt FROM T3 WHERE [Date1] < CAST(GetDate()-3 AS DATE)) AS t3
CROSS JOIN
(SELECT COUNT(*) AS Cnt FROM T4 WHERE [Date1] < CAST(GetDate()-3 AS DATE)) AS t4
Or a CROSS APPLY
SELECT
t1.Cnt AS [T1],
t2.Cnt AS [T2],
t3.Cnt AS [T3],
t4.Cnt AS [T4],
(t1.Cnt + t2.Cnt + t3.Cnt + t4.Cnt) AS [T1234]
FROM (SELECT CAST(GetDate()-3 AS DATE) as Dt) d
CROSS APPLY (SELECT COUNT(*) AS Cnt FROM T1 WHERE [Date1] < d.Dt) AS t1
CROSS APPLY (SELECT COUNT(*) AS Cnt FROM T2 WHERE [Date1] < d.Dt) AS t2
CROSS APPLY (SELECT COUNT(*) AS Cnt FROM T3 WHERE [Date1] < d.Dt) AS t3
CROSS APPLY (SELECT COUNT(*) AS Cnt FROM T4 WHERE [Date1] < d.Dt) AS t4
Example snippet for Sql Server:
declare #T1 table (id int primary key identity(1,1), [Date1] date);
declare #T2 table (id int primary key identity(1,1), [Date1] date);
declare #T3 table (id int primary key identity(1,1), [Date1] date);
declare #T4 table (id int primary key identity(1,1), [Date1] date);
insert into #T1 ([Date1]) values (getdate()-6),(getdate()-5),(getdate()-4),(getdate()-3),(getdate()-2),(getdate()-1),(getdate()-0);
insert into #T2 ([Date1]) select top 6 [Date1] from #T1 order by [Date1] desc;
insert into #T3 ([Date1]) select top 5 [Date1] from #T1 order by [Date1] desc;
insert into #T4 ([Date1]) select top 4 [Date1] from #T1 order by [Date1] desc;
SELECT
t1.Cnt AS [T1],
t2.Cnt AS [T2],
t3.Cnt AS [T3],
t4.Cnt AS [T4],
(t1.Cnt + t2.Cnt + t3.Cnt + t4.Cnt) AS [T1234]
FROM
(SELECT COUNT(*) AS Cnt FROM #T1 WHERE [Date1] < CAST(GetDate()-3 AS DATE)) AS t1
CROSS JOIN
(SELECT COUNT(*) AS Cnt FROM #T2 WHERE [Date1] < CAST(GetDate()-3 AS DATE)) AS t2
CROSS JOIN
(SELECT COUNT(*) AS Cnt FROM #T3 WHERE [Date1] < CAST(GetDate()-3 AS DATE)) AS t3
CROSS JOIN
(SELECT COUNT(*) AS Cnt FROM #T4 WHERE [Date1] < CAST(GetDate()-3 AS DATE)) AS t4
Returns:
T1 T2 T3 T4 T1234
3 2 1 0 6
Instead create a view, you can use a CTE (Common Table Expression). It works like a view, but not persists on database. Please try it:
WITH CteDate( Date1 )
AS ( SELECT Date1 FROM t1 UNION ALL
SELECT Date1 FROM t2 UNION ALL
SELECT Date1 FROM t3 UNION ALL
SELECT Date1 FROM t4
)
SELECT COUNT(*) FROM CteDate WHERE Date1 <= DATEADD(DAY, -3, GETDATE())
It works for all SQL Server greater or equal then 2005.
Input : Keep the column value into next line if word to word space is 3 space and length of the word is >9 .
declare #Table table(CL1 varchar(50))
INSERT INTO #Table
SELECT 'Ohh my GOD'
UNION ALL
SELECT 'hindunewspaer is no1 paper'
select * from #Table
o/p :
CL1
ohh
my god
hindunewpaer
is no1 paper
Used a Split/Parse function. Can be inline if needed.
EDIT - Switch to a Parser which is not limited to 8K because the final
string could easily be larger than 8K
Example
;with cte0 as (
Select Seq=Row_Number() over (Order by (Select null)),RetSeq,RetVal
From #Table A
Cross Apply (
Select RetSeq
,RetVal=case when len(RetVal)>9 then '~~~' else '' end+RetVal+case when len(RetVal)>9 then '~~~' else '' end
From [dbo].[udf-Str-Parse](Replace(CL1,' ','~~~ '),' ')
) B ),
cte1 as ( Select S=Stuff((Select ' '+RetVal From cte0 Order by Seq For XML Path ('')),1,1,'') )
Select CL1 = RetVal
From cte1 A
Cross Apply [dbo].[udf-Str-Parse](A.S,'~~~') B
Order By RetSeq
Returns
CL1
Ohh
my GOD
hindunewspaer
is no1 paper
The Split/Parse Function if Needed
CREATE FUNCTION [dbo].[udf-Str-Parse] (#String varchar(max),#Delimiter varchar(10))
Returns Table
As
Return (
Select RetSeq = Row_Number() over (Order By (Select null))
,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)')))
From (Select x = Cast('<x>' + replace((Select replace(#String,#Delimiter,'§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A
Cross Apply x.nodes('x') AS B(i)
);
--Thanks Shnugo for making this XML safe
--Select * from [dbo].[udf-Str-Parse]('Dog,Cat,House,Car',',')
--Select * from [dbo].[udf-Str-Parse]('John Cappelletti was here',' ')
--Select * from [dbo].[udf-Str-Parse]('this,is,<test>,for,< & >',',')
I need to get a tree of related nodes given a certain node, but not necessary top node. I've got a solution using two CTEs, since I am struggling to squeeze it all into one CTE :). Might somebody have a sleek solution to avoid using two CTEs? Here is some code that I was playing with:
DECLARE #temp AS TABLE (ID INT, ParentID INT)
INSERT INTO #temp
SELECT 1 ID, NULL AS ParentID
UNION ALL
SELECT 2, 1
UNION ALL
SELECT 3, 2
UNION ALL
SELECT 4, 3
UNION ALL
SELECT 5, 4
UNION ALL
SELECT 6, NULL
UNION ALL
SELECT 7, 6
UNION ALL
SELECT 8, 7
DECLARE #startNode INT = 4
;WITH TheTree (ID,ParentID)
AS (
SELECT ID, ParentID
FROM #temp
WHERE ID = #startNode
UNION ALL
SELECT t.id, t.ParentID
FROM #temp t
JOIN TheTree tr ON t.ParentID = tr.ID
)
SELECT * FROM TheTree
;WITH Up(ID,ParentID)
AS (
SELECT t.id, t.ParentID
FROM #temp t
WHERE t.ID = #startNode
UNION ALL
SELECT t.id, t.ParentID
FROM #temp t
JOIN Up c ON t.id = c.ParentID
)
--SELECT * FROM Up
,TheTree (ID,ParentID)
AS (
SELECT ID, ParentID
FROM Up
WHERE ParentID is null
UNION ALL
SELECT t.id, t.ParentID
FROM #temp t
JOIN TheTree tr ON t.ParentID = tr.ID
)
SELECT * FROM TheTree
thanks
Meh. This avoids using two CTEs, but the result is a brute force kludge that hardly qualifies as "sleek" as it won’t be efficient if your table is at all sizeable. It will:
Recursively build all possible hierarchies
As you build them, flag the target NodeId as you find it
Return only the targeted tree
I threw in column “TreeNumber” on the off-chance the TargetId appears in multiple hierarchies, or if you’d ever have multiple values to check in one pass. “Depth” was added to make the output a bit more legible.
A more complex solution like #John’s might do, and more and subtler tricks could be done with more detailed table sturctures.
DECLARE #startNode INT = 4
;WITH cteAllTrees (TreeNumber, Depth, ID, ParentID, ContainsTarget)
AS (
SELECT
row_number() over (order by ID) TreeNumber
,1
,ID
,ParentID
,case
when ID = #startNode then 1
else 0
end ContainsTarget
FROM #temp
WHERE ParentId is null
UNION ALL
SELECT
tr.TreeNumber
,tr.Depth + 1
,t.id
,t.ParentID
,case
when tr.ContainsTarget = 1 then 1
when t.ID = #startNode then 1
else 0
end ContainsTarget
FROM #temp t
INNER JOIN cteAllTrees tr
ON t.ParentID = tr.ID
)
SELECT
TreeNumber
,Depth
,ID
,ParentId
from cteAllTrees
where TreeNumber in (select TreeNumber from cteAllTrees where ContainsTarget = 1)
order by
TreeNumber
,Depth
,ID
Here is a technique where you can select the entire hierarchy, a specific node with all its children, and even a filtered list and how they roll.
Note: See the comments next to the DECLAREs
Declare #YourTable table (id int,pt int,name varchar(50))
Insert into #YourTable values
(1,null,'1'),(2,1,'2'),(3,1,'3'),(4,2,'4'),(5,2,'5'),(6,3,'6'),(7,null,'7'),(8,7,'8')
Declare #Top int = null --<< Sets top of Hier Try 2
Declare #Nest varchar(25) = '|-----' --<< Optional: Added for readability
Declare #Filter varchar(25) = '' --<< Empty for All or try 4,6
;with cteP as (
Select Seq = cast(1000+Row_Number() over (Order by name) as varchar(500))
,ID
,pt
,Lvl=1
,name
From #YourTable
Where IsNull(#Top,-1) = case when #Top is null then isnull(pt,-1) else ID end
Union All
Select Seq = cast(concat(p.Seq,'.',1000+Row_Number() over (Order by r.name)) as varchar(500))
,r.ID
,r.pt
,p.Lvl+1
,r.name
From #YourTable r
Join cteP p on r.pt = p.ID)
,cteR1 as (Select *,R1=Row_Number() over (Order By Seq) From cteP)
,cteR2 as (Select A.Seq,A.ID,R2=Max(B.R1) From cteR1 A Join cteR1 B on (B.Seq like A.Seq+'%') Group By A.Seq,A.ID )
Select Distinct
A.R1
,B.R2
,A.ID
,A.pt
,A.Lvl
,name = Replicate(#Nest,A.Lvl-1) + A.name
From cteR1 A
Join cteR2 B on A.ID=B.ID
Join (Select R1 From cteR1 where IIF(#Filter='',1,0)+CharIndex(concat(',',ID,','),concat(',',#Filter+','))>0) F on F.R1 between A.R1 and B.R2
Order By A.R1
If I have a table:
ID NAME
1 Red
2 Blue
3 Green
How can I return a query so that my result is:
Col1 Col2 Col3
Red Blue Green
Would I just do an inner join on itself or would I need a pivot table?
Yes, you can do it with join, eg:
select t1.name col1, t2.name col2, t3.name col3
from yourtable t1
join yourtable t2 on t2.id=2
join yourtable t3 on t3.id=3
where t1.id=1;
Or you can simply do it with embedded select statements, like:
In MySQL:
select
(select name from yourtable where id=1) col1,
(select name from yourtable where id=2) col2,
(select name from yourtable where id=3) col3;
In Oracle:
select
(select name from yourtable where id=1) col1,
(select name from yourtable where id=2) col2,
(select name from yourtable where id=3) col3
from dual;
Of course in that query the number of cols is fixed, you must edit it if you add more rows to roll up.
you can use dynamic SQL with PIVOT:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(id)
from yourtable
group by ColumnName, id
order by id
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = N'SELECT ' + #cols + N' from
(
select id, ColumnName
from yourtable
) x
pivot
(
max(ColumnName)
for id in (' + #cols + N')
) p '
exec sp_executesql #query;
I have to make query on WITH query, something like
; WITH #table1
(
SELECT id, x from ... WHERE....
UNION ALL
SELECT id, x from ... WHERE...
)
WITH #table2
(
SELECT DISTINCT tbl_x.*,ROW_NUMBER() OVER (order by id) as RowNumber
WHERE id in ( SELECT id from #table1)
)
SELECT * FROM #table2 WHERE RowNumber > ... and ...
So I have to use WITH on WITH and then SELECT on second WITH, How I can do that?
You can define multiple CTEs after the WITH keyword by separating each CTE with a comma.
WITH T1 AS
(
SELECT id, x from ... WHERE....
UNION ALL
SELECT id, x from ... WHERE...
)
, T2 AS
(
SELECT DISTINCT tbl_x.*, ROW_NUMBER() OVER (order by id) as RowNumber
WHERE id in ( SELECT id from T1 )
)
SELECT * FROM T2 WHERE RowNumber > ... and ...
https://web.archive.org/web/20210927200924/http://www.4guysfromrolla.com/webtech/071906-1.shtml