I have got a table in SQL Server 2008 looking like this
FIELD1;FIELD2;FIELD3;FIELD4
-------------------------------
TEST1 ;AAAAAA;NULL ;NULL
TEST1 ;NULL ;BBBBBB;NULL
TEST1 ;NULL ;NULL ;CCCC
TEST2 ;XXXXXX;NULL ;NULL
TEST2 ;NULL ;YYYYYY;NULL
TEST2 ;NULL ;NULL ;ZZZZ
TEST3 ;UUUUUU;VVVVVV;NULL
and I want a result like this:
FIELD1;FIELD2;FIELD3;FIELD4
TEST1 ;AAAAAA;BBBBBB;CCCC
TEST2 ;XXXXXX;YYYYYY;ZZZZ
TEST3 ;UUUUUU;VVVVVV;NULL
Is there a good way to achieve this?
A simple way do achieve it is to use subqueries on the select.
declare #MyTable table
(
FIELD1 varchar(50)
,FIELD2 varchar(50)
,FIELD3 varchar(50)
,FIELD4 varchar(50)
)
insert into #MyTable values
('TEST1', 'AAAAAA', NULL , NULL)
,('TEST1', NULL , 'BBBBBB', NULL)
,('TEST1', NULL , NULL , 'CCCC')
,('TEST2', 'XXXXXX', NULL , NULL)
,('TEST2', NULL ,'YYYYYY', NULL)
,('TEST2', NULL ,NULL ,'ZZZZ')
,('TEST3', 'UUUUUU','VVVVVV', NULL)
select * from #MyTable t0
select t1.FIELD1
, (select top 1 t2.FIELD2 from #MyTable t2 where t2.FIELD2 is not null and t2.FIELD1 = t1.Field1)
, (select top 1 t3.FIELD3 from #MyTable t3 where t3.FIELD3 is not null and t3.FIELD1 = t1.Field1)
, (select top 1 t4.FIELD4 from #MyTable t4 where t4.FIELD4 is not null and t4.FIELD1 = t1.Field1)
from #MyTable t1
group by t1.FIELD1
static solution is here:
SELECT a.FIELD1,a.FIELD2,b.FIELD3,c.FIELD4
FROM YourTable a
LEFT JOIN YourTable b ON a.FIELD1 = b.FIELD1 AND b.FIELD3 IS NOT NULL
LEFT JOIN YourTable c ON a.FIELD1 = c.FIELD1 AND c.FIELD4 IS NOT NULL
WHERE a.FIELD2 IS NOT NULL
Related
I found some solutions to replace (below example) #test.col2 with data from #test2.src. But in the result it just selects a single random value and replaces them all with it. How to fix? Thanks!
#test (the target table)
col1 col2
-------------
A 1
B 2
C 3
D 4
E 5
#test2 (the source table)
src1
sample1
sample2
sample3
Query:
UPDATE #test
SET col1 = data1.LastName
FROM #test
CROSS APPLY
(SELECT TOP(1) #test2.LastName
FROM #test2
ORDER BY NEWID()) data1
Example result:
col1 col2
----------------
A sample2
B sample2
C sample2
D sample2
E sample2
Here is one way to tackle this. It is using ROW_NUMBER in a cte to "randomize" the values.
if OBJECT_ID('tempdb..#test') is not null
drop table #test;
create table #test
(
col1 varchar(20)
, col2 int
);
insert #test
select 'A', 1 union all
select 'B', 2 union all
select 'C', 3 union all
select 'D', 4 union all
select 'E', 5;
if OBJECT_ID('tempdb..#test2') is not null
drop table #test2;
create table #test2
(
LastName varchar(20)
);
insert #test2
select 'src1' union all
select 'sample1' union all
select 'sample2' union all
select 'sample3';
--here is the data before any updates
select * from #test;
with t1 as
(
select col1
, col2
, RowNum = ROW_NUMBER() over(order by newid())
from #test
)
, t2 as
(
select LastName
, RowNum = ROW_NUMBER() over(order by newid())
from #test2
)
update t
set col1 = t2.LastName
from t1
join t2 on t1.RowNum = t2.RowNum
join #test t on t.col1 = t1.col1
--we now have updated with a "random" row
select * from #test;
I have a view with a union all table, a person may belong to one or many table.
how do i create a query that will add a column with a ';' delimited where the person belong to, the ID is unique per person.
here's the example
--table1
PID fName tableMem
1 test group1
2 test2 group1
--table2
PID fName tableMem
1 test group2
3 test3 group2
--table3
PID fName tableMem
1 test group3
3 test3 group3
Here's the output I wanted
--compiled table after union of all the 3 tables
PID fname tableMem
1 test group1;group2;group3
2 test2 group1
3 test3 group2;group3
Here's the query I built from reading here for the past 2 days.I'm using STUFF and partition because I need the row to be distinct and this query will run as view.
SELECT *
FROM
(SELECT
*,
ROW_NUMBER() OVER(PARTITION BY PIP ORDER BY Fname) AS rownum
FROM
(SELECT
*,
STUFF((SELECT ';'+ di.tablemem
FROM DPI di <<-- alias table from union
WHERE DPI.PID = di.PID
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '') tablemem
FROM
(SELECT *
FROM
(--table1
SELECT 'group1' AS tableMem, * FROM table1
UNION ALL
--table2
SELECT 'group2' AS tableMem, * FROM table2
UNION ALL
--table3
SELECT 'group3' AS tableMem, * FROM table3) AS DPI <<--alias table name
) AS innertable
) AS distinctTable
) AS outerTable
WHERE
rownum = 1
what am I missing or what is wrong with the query. I'm guessing its because Im using a derived table name of the union sub select. is there any workaround?
Thank you in advance
You need GROUP BY data by PID, fName, using the FOR XML aggregation it would be
WITH DPI AS (
--table1
Select 'group1' as tableMem,* from table1
UNION ALL
--table2
Select 'group2' as tableMem,* from table2
UNION ALL
--table3
Select 'group3' as tableMem,* from table3
)
SELECT PID, fName
, STUFF((
SELECT ';'+ di.tablemem
FROM DPI di
WHERE di.PID = di1.PID
FOR XML PATH(''),TYPE).value('.','NVARCHAR(MAX)'),1,1,'') tablemem
FROM DPI di1
GROUP BY PID, fName;
Here is a possible solution using CTE:
;with cte as (
select * from #tbl1
union all
select * from #tbl2
union all
select * from #tbl3
)
select distinct
pid
,fname
,stuff(
(select '; ' + tableMem
from cte
where pid = a.pid
and fname = a.fname
FOR XML PATH(''),TYPE)
.value('text()[1]','nvarchar(max)'),1,2,N'') as tableMem
from cte a
Given that you have a finite number of tables, I think I find this simpler:
select p.pid, p.fname,
trim(';' from
(case when t1.pid is not null then 'group1;' else '' end) +
(case when t2.pid is not null then 'group2;' else '' end) +
(case when t3.pid is not null then 'group3;' else '' end)
) as groups
from (select pid, fname from table1 union -- on purpose to remove duplicates
select pid, fname from table2 union
select pid, fname from table3
) p left join
table1 t1
on t1.pid = p.pid left join
table2 t2
on t2.pid = p.pid left join
table3 t3
on t3.pid = p.pid;
The most recent version of SQL Server supports string_agg(), which would make this simpler still.
Try this:
DECLARE #table1 TABLE
(
[PID] TINYINT
,[fname] VARCHAR(12)
,[tableMem] VARCHAR(12)
);
DECLARE #table2 TABLE
(
[PID] TINYINT
,[fname] VARCHAR(12)
,[tableMem] VARCHAR(12)
);
DECLARE #table3 TABLE
(
[PID] TINYINT
,[fname] VARCHAR(12)
,[tableMem] VARCHAR(12)
);
INSERT INTO #table1 ([PID], [fname], [tableMem])
VALUES (1, 'test', 'group1')
,(2, 'test2', 'group1');
INSERT INTO #table2 ([PID], [fname], [tableMem])
VALUES (1, 'test', 'group2')
,(3, 'test3 ', 'group2');
INSERT INTO #table3 ([PID], [fname], [tableMem])
VALUES (1, 'test', 'group3')
,(3, 'test3 ', 'group3');
WITH DataSource AS
(
SELECT *
FROM #table1
UNION ALL
SELECT *
FROM #table2
UNION ALL
SELECT *
FROM #table3
)
SELECT DISTINCT DS.[PID]
,DS.fname
,CSVvalue.[tableMem]
FROM DataSource DS
CROSS APPLY
(
SELECT STUFF
(
(
SELECT ',' + DS1.[tableMem]
FROM DataSource DS1
WHERE DS.[PID] = DS1.[PID]
AND DS.[fname] = DS1.[fname]
ORDER BY DS1.[tableMem]
FOR XML PATH(''), TYPE
).value('.', 'VARCHAR(MAX)')
,1
,1
,''
)
) CSVvalue ([tableMem]);
I have 2 tables and structure is same on both tables.
Table 1:
ID Name Phone
1 xxx 111
2 yyy 222
Table 2:
ID Name Phone
1 xxx 111
3 zzz 333
I need to compare these two tables and display the results (based on ID column- where condition ID) as
Available in both tables
Table1 only
Table2 only
This should be like this,
ID Name Phone Status
----------------------------------------
1 xxx 111 Available in both
2 yyy 222 Available in T1 only
3 zzz 333 Available in T2 only
using HASHBYTES :Demo Here ..you dont need to consume table mutiple times,but only once
;with cte
as
(
select id,name,phone,hashbytes('sha1',concat(id,name,phone) )as tb1
from #t1
)
select isnull(c.id,b.id) as id,
isnull(c.name,b.name) as name,
isnull(c.phone,b.phone) as phone,
case when c.tb1 is null then 'exists in second table only'
when c.tb1 is not null and b.tb1 is not null then 'exists in both'
when b.tb1 is null then 'exists in first table only'
end as 'exidts' from cte c
full join
(
select id,name,phone,hashbytes('sha1',concat(id,name,phone) )as tb1
from #t2
) b
on
b.tb1=c.tb1
Try this:
declare #table1 table
(
name varchar(10),
phone varchar(10)
)
declare #table2 table
(
name varchar(10),
phone varchar(10)
)
INSERT INTO #table1 VALUES('xxx','111')
INSERT INTO #table1 VALUES('yyy','222')
INSERT INTO #table2 VALUES('xxx','111')
INSERT INTO #table2 VALUES('zzz','333')
SELECT t1.name, t1.phone, 'Available on both' FROM
#table1 t1 INNER JOIN #table2 t2
ON t1.name = t2.name and t1.phone = t2.phone
UNION
SELECT name, phone, 'Available on T1 only' FROM
#table1 t1 WHERE NOT EXISTS
(SELECT 1 FROM #table2 t2
WHERE t1.name = t2.name and t1.phone = t2.phone)
UNION
SELECT name, phone, 'Available on T2 only' FROM
#table2 t2 WHERE NOT EXISTS
(SELECT 1 FROM #table1 t1
WHERE t1.name = t2.name and t1.phone = t2.phone)
You can use combination of FULL JOIN and IS NULL to check availability from both tables -
SELECT ISNULL(t1.id, t2.id) AS Id
, ISNULL(t1.name, t2.name) AS Name
, ISNULL(t1.phone, t2.phone) AS Phone
, CASE
WHEN t1.id IS NULL THEN 'Available in T2 only'
WHEN t2.id IS NULL THEN 'Available in T1 only'
ELSE 'Available in both'
END AS Status
FROM Table1 AS t1
FULL JOIN Table2 AS t2 ON (t2.id = t1.id);
As this query uses only one JOIN operation and no sub queries it is very fast.
This could work:
CREATE TABLE #T1 ( ID INT, Name VARCHAR(10), Phone VARCHAR(10) )
CREATE TABLE #T2 ( ID INT, Name VARCHAR(10), Phone VARCHAR(10) )
INSERT INTO #T1 VALUES ( 1, 'xxx', '111' ), ( 2, 'yyy', '222' )
INSERT INTO #T2 VALUES ( 1, 'xxx', '111' ), ( 3, 'zzz', '333' )
SELECT #T1.ID, #T1.Name, #T1.Phone, 'Available on both' AS Status
FROM #T1 INNER JOIN #T2 ON #T1.ID = #T2.ID
UNION
SELECT #T1.ID, #T1.Name, #T1.Phone, 'Available on T1 only' AS Status
FROM #T1 LEFT JOIN #T2 ON #T1.ID = #T2.ID
WHERE #T2.ID IS NULL
UNION
SELECT #T2.ID, #T2.Name, #T2.Phone, 'Available on T2 only' AS Status
FROM #T1 RIGHT JOIN #T2 ON #T1.ID = #T2.ID
WHERE #T1.ID IS NULL
DROP TABLE #T1
DROP TABLE #T2
I am getting error in the below sql query.
if count is >1 i need to execute when statement, if not else statement.
SELECT CASE
WHEN (COUNT(VALUE) FROM TABLE1 WHERE ID=111)>1 )
THEN
SELECT VALUE FROM TABLE2 WHERE ID=111
ELSE
SELECT 2
Please help
Try this:
if (select count(*) from table1 where id = 111 group by id) > 1
select value from table2 where id = 111
else
select 2
Demo
The same thing, written using case when...
select
case
when (select count(*) from table1 where id = 111 group by id) > 1 then value
else 2
end
from table2
where id = 111
Try this sample code
DECLARE #Table1 TABLE
(
id INT,
value INT
)
INSERT #Table1
VALUES(1,
10)
INSERT #Table1
VALUES(2,
20)
DECLARE #TABLE2 TABLE
(
id INT,
c2 INT
)
INSERT #TABLE2
VALUES(1,
11 )
INSERT #TABLE2
VALUES(2,
22 )
SELECT CASE
WHEN (SELECT count(value)
FROM #Table1) > 0 THEN (SELECT T2.c2
FROM #TABLE2 T2
WHERE T1.id = T2.id)
ELSE (SELECT T2.id
FROM #TABLE2 T2
WHERE T1.id = T2.id)
END
FROM #Table1 t1
IF EXISTS(SELECT TOP 1 1 FROM TABLE1 WHERE ID='111' HAVING COUNT(VALUE)>1)
BEGIN
SELECT VALUE FROM TABLE2 WHERE ID=111
END
ELSE
BEGIN
SELECT 2
END
I have the following hierarchical table:
Table Category:
CategoryId, ParentCategoryId, CategoryName
1, null, SomeRoot
2, 1, SomeChild
3, 2, SomeGrandchild
4, 3, SomeGreatGrandchild
(note this sample data doesn't include a leaf on an earlier node than level 4, but that is possible). The data will never go deeper than level 4, if that is relevant. I'd like to transform/pivot it to this fixed 4 level display
CatId, Name1, Name2, Name3, Name4
1, SomeRoot, null, null, null
2, SomeRoot, SomeChild, null, null
3, SomeRoot, SomeChild, SomeGrandchild, null
4, SomeRoot, SomeChild, SomeGrandchild, SomeGreatGrandchild
I've done left outer joining to the category table 4 times, and built a huge case statement for detecting the level to use for the ID field, but that doesn't include the null rows.... Any ideas? HELP!
this probably isn't the most efficient query, but it is the easiest to code:
declare #YourTable table (CategoryId int primary key, ParentCategoryId int , CategoryName varchar(50))
INSERT INTO #YourTable VALUES (1, null, 'SomeRoot')
INSERT INTO #YourTable VALUES (2, 1, 'SomeChild')
INSERT INTO #YourTable VALUES (3, 2, 'SomeGrandchild')
INSERT INTO #YourTable VALUES (4, 3, 'SomeGreatGrandchild')
INSERT INTO #YourTable VALUES (10, null, 'X_SomeRoot')
INSERT INTO #YourTable VALUES (20, 10, 'X_SomeChild')
INSERT INTO #YourTable VALUES (30, 20, 'X_SomeGrandchild')
Select
c1.CategoryId, c1.CategoryName, c2.CategoryName, c3.CategoryName, c4.CategoryName
From #YourTable c1
INNER JOIN #YourTable c2 On c1.CategoryId = c2.ParentCategoryId
INNER JOIN #YourTable c3 On c2.CategoryId = c3.ParentCategoryId
INNER JOIN #YourTable c4 On c3.CategoryId = c4.ParentCategoryId
WHERE c1.ParentCategoryId IS NULL
UNION
Select
c1.CategoryId, c1.CategoryName, c2.CategoryName, c3.CategoryName, NULL
From #YourTable c1
INNER JOIN #YourTable c2 On c1.CategoryId = c2.ParentCategoryId
INNER JOIN #YourTable c3 On c2.CategoryId = c3.ParentCategoryId
WHERE c1.ParentCategoryId IS NULL
UNION
Select
c1.CategoryId, c1.CategoryName, c2.CategoryName, NULL, NULL
From #YourTable c1
INNER JOIN #YourTable c2 On c1.CategoryId = c2.ParentCategoryId
WHERE c1.ParentCategoryId IS NULL
UNION
Select
c1.CategoryId, c1.CategoryName, NULL, NULL, NULL
From #YourTable c1
WHERE c1.ParentCategoryId IS NULL
ORDER BY 2,3,4,5
OUTPUT:
SortB CategoryId CategoryName CategoryName CategoryName CategoryName
----- ----------- ------------ ------------- ----------------- --------------------
1 1 SomeRoot NULL NULL NULL
2 1 SomeRoot SomeChild NULL NULL
3 1 SomeRoot SomeChild SomeGrandchild NULL
4 1 SomeRoot SomeChild SomeGrandchild SomeGreatGrandchild
1 10 X_SomeRoot NULL NULL NULL
2 10 X_SomeRoot X_SomeChild NULL NULL
3 10 X_SomeRoot X_SomeChild X_SomeGrandchild NULL
(7 row(s) affected)
Try this:
Select C.CatId, C.Name, PC.Name, GP.Name, GGP.Name
From Category C
Left Join Category PC On PC.CatId = C.ParentCategoryId
Left Join Category GP On GP .CatId = PC.ParentCategoryId
Left Join Category GGP On GGP .CatId = GP.ParentCategoryId
Based on yr comment, if you write a UDF as follows:
Create Function CatParentNames
( #CatId Integer )
Returns varchar(1000)
AS
Begin
Declare #outVal VarChar(1000)
Declare #ParId Integer
Select #ParId = ParentCategoryId, #outVal = Name
From Category
Where CatId = #CatId
While Exists(Select * From Category
Where CatId = #ParId)
Begin
Select #ParId = ParentCategoryId,
#outVal = Name + ', ' + #outVal
From Category
Where CatId = #ParId
End
Return #outVal
End
then, write your sql as follows:
Select CatId, dbo.CatParentNames(CatId)
From Category
Where ParentCategoryId Is Not Null
Try this:
select a.CategoryId as CatId,
a.CategoryName as Name1,
cast(null as varchar(20)) as Name2,
cast(null as varchar(20)) as Name3,
cast(null as varchar(20)) as Name4
from #YourTable a
where a.ParentCategoryId is null
union all
select b.CategoryId,
a.CategoryName,
b.CategoryName,
null,
null
from #YourTable a
inner join #YourTable b
on a.CategoryId = b.ParentCategoryId
where a.ParentCategoryId is null
union all
select c.CategoryId,
a.CategoryName,
b.CategoryName,
c.CategoryName,
null
from #YourTable a
inner join #YourTable b
on a.CategoryId = b.ParentCategoryId
inner join #YourTable c
on b.CategoryId = c.ParentCategoryId
where a.ParentCategoryId is null
union all
select d.CategoryId,
a.CategoryName,
b.CategoryName,
c.CategoryName,
d.CategoryName
from #YourTable a
inner join #YourTable b
on a.CategoryId = b.ParentCategoryId
inner join #YourTable c
on b.CategoryId = c.ParentCategoryId
inner join #YourTable d
on c.CategoryId = d.ParentCategoryId
order by 2, 3, 4, 5
But that is not the way to build it if you are going to use it with a multi-column TreeView that looks like this:
(source: digitaltools.com)
More can be found here.