updating a column in a table having duplicate rows - sql

having problem updating a column in a table having duplicate rows..
I have a table "tab1" and its data looks like this..
Id col2 col3 col4 col5 col6 col7
1 xim M gtt tif 1 2
2 white M abc png 0 25
2 white M abc jpeg 0 25
3 gtc V ftt gif 4 72
This table contains duplicate Id's but differ only in col5.
this table contains around 4000 rows
i'd like to update col5 such that the output looks like this..
Id col2 col3 col4 col5 col6 col7
1 xim M gtt tif 1 2
2 white M abc png,jpeg 0 25
3 gtc V ftt gif 4 72
Is there a way to update this table using update statement, do i have to create a temp table for this update..??

I agree with the comments posted with by njk and Tony. It's not a good idea to denormalize your database, but perhaps your end goal is not so obvious and combining the image extensions is appropriate for your particular need.
This does what you are asking. I'm sure there's a way to do it with XML too without using a cursor in a function...
use tempdb
go
create table tmp (
id int,
col2 varchar(10),
col3 varchar(10),
col4 varchar(10),
col5 varchar(255),
col6 int,
col7 int
)
go
insert into tmp values
(1, 'xim', 'M', 'gtt', 'tif', 1, 2),
(2, 'white', 'M', 'abc', 'png', 0, 25),
(2, 'white', 'M', 'abc', 'jpeg', 0, 25),
(2, 'white', 'M', 'abc', 'gif', 0, 25),
(3, 'gtc', 'V', 'ftt', 'jpeg', 4, 72),
(3, 'gtc', 'V', 'ftt', 'tif', 4, 72),
(3, 'gtc', 'V', 'ftt', 'png', 4, 72),
(3, 'gtc', 'V', 'ftt', 'gif', 4, 72)
go
create function fnConcatCol5 (#id int) returns varchar(255) as
begin
declare #rtn varchar(255) = '', #val varchar(10)
declare cr cursor local for
select col5 from tmp where id = #id
open cr
fetch next from cr into #val
while ##fetch_status = 0
begin
set #rtn = #rtn + #val + ','
fetch next from cr into #val
end
close cr
deallocate cr
set #rtn = left(#rtn, datalength(#rtn) - 1)
return #rtn
end
go
-- it is more efficient to split up the 'distinct' and function call
-- into separate SQL statements so the function is only run *one* time
-- for each unique id
select distinct id, col2, col3, col4, col6, col7
into #temp
from tmp
select id, col2, col3, col4, dbo.fnConcatCol5(id) as col5, col6, col7
from #temp
go
drop table tmp, #temp
go
drop function fnConcatCol5
go
The data returned looks like this:
id col2 col3 col4 col5 col6 col7
----- ------- ------- ------- ------------------- ------- ----
1 xim M gtt tif 1 2
2 white M abc png,jpeg,gif 0 25
3 gtc V ftt jpeg,tif,png,gif 4 72

Related

Select not null columns dynamically from a table to join with other table

I have table1 as below
Col1 col2 col3 col4 col5 col6
1 a b c d 4
1 a b f g 4
2 a i j k 5
2 l m n o 4
3 l m n o 4
3 p q q s 6
3 t u v w 7
I have table2 as below
RowNumber col1 col2 col3 col4 col5 count_of_records
1 1 a null null null 2
2 2 a i null null 1
3 3 null null null null 3
We have to delete the records from table1 using records from table2.
Example, for first row in table2, we have to join it with table1 and get the count of records in table1. here only two columns are joined as only those two are not null values in table2 in first record.
query will be
SELECT count(*)
FROM table1
inner join table2
on table1.col1 = table2.col1
and table1.col2 = table2.col2
where rownumber =1
output : 2
if this count matches with count_of_records in table2 we have to delete this record. In this case as count is matching we need to generate one delete query
DELETE FROM table1
inner join table2
on table1.col1 = table2.col1
and table1.col2 = table2.col2
Please suggest a way to achieve this dynamically for each row in table2. We can do it either using SQL or SSIS.
I believe this will give you what you are looking for. If you are on SQL Server 2016 or greater, you can replace the IF OBJECT_ID() checks with DROP TABLE IF EXISTS.
The trick is in the join between the two tables, which has null checks for each one. If the column is null, it ignores the join. I assumed col1 was always equal since it appeared that way in your metadata. If not, it can be modified to match the other join predicates.
IF OBJECT_ID('tempdb..#table1') IS NOT NULL DROP TABLE #table1
CREATE TABLE #table1
(
col1 INT
, col2 CHAR(1)
, col3 CHAR(1)
, col4 CHAR(1)
, col5 CHAR(1)
, col6 INT
)
IF OBJECT_ID('tempdb..#table2') IS NOT NULL DROP TABLE #table2
CREATE TABLE #table2
(
RowNumber INT
, col1 INT
, col2 CHAR(1)
, col3 CHAR(1)
, col4 CHAR(1)
, col5 CHAR(1)
, count_of_records INT
)
INSERT INTO #table1 (col1, col2, col3, col4, col5, col6) VALUES
(1, 'a', 'b', 'c', 'd', 4),
(1, 'a', 'b', 'f', 'g', 4),
(2, 'a', 'i', 'j', 'k', 5),
(2, 'l', 'm', 'n', 'o', 4),
(3, 'l', 'm', 'n', 'o', 4),
(3, 'p', 'q', 'q', 's', 6),
(3, 't', 'u', 'v', 'w', 7)
INSERT INTO #table2 (RowNumber, col1, col2, col3, col4, col5, count_of_records) VALUES
(1, 1, 'a', null, null, null, 2),
(2, 2, 'a', 'i', null, null, 1),
(3, 3, null, null, null, null, 3)
IF OBJECT_ID('tempdb..#counts') IS NOT NULL DROP TABLE #counts
CREATE TABLE #counts
(
RowNumber INT
, original_count INT
, record_count INT
)
INSERT INTO #counts (RowNumber, original_count, record_count)
SELECT
RowNumber
, count_of_records
, COUNT(*) AS record_count
FROM
#table2 t2
INNER JOIN #table1 t1
ON t2.col1 = t1.col1
AND (t2.col2 IS NULL OR t2.col2 = t1.col2)
AND (t2.col3 IS NULL OR t2.col3 = t1.col3)
AND (t2.col4 IS NULL OR t2.col4 = t1.col4)
AND (t2.col5 IS NULL OR t2.col5 = t1.col5)
GROUP BY
RowNumber
, count_of_records
DELETE t1
FROM
#table1 t1
INNER JOIN #counts c
ON t1.Col1 = c.RowNumber
AND c.original_count = c.record_count
SELECT COUNT(*) FROM #table1

Addition with NULL values across multiple columns

Col1 Col2 Col3 SumCol
4 9 NULL 13
NULL 8 2 10
8 3 NULL 11
NULL 5 5 10
I have a table populated with columns Col1, Col2, and Col3, and I am trying to create a new column, SumCol. I know addition with NULL values is annoying so I appreciate any help
you can use below queries in sql-server
select id, col1, col2, col3, (coalesce(col1, 0) + coalesce(col2, 0) + coalesce(col3, 0)) total
from #tbl
OR
select id, col1, col2, col3, (ISNULL(col1, 0) + ISNULL(col2, 0) + ISNULL(col3, 0)) total
from #tbl
It is very simple by using XQuery or COALESCE().
SQL #1
-- DDL and sample data population, start
DECLARE #tbl TABLE (ID INT IDENTITY PRIMARY KEY, Col1 INT, Col2 INT, Col3 INT);
INSERT INTO #tbl (Col1, Col2, Col3) VALUES
( 4 , 9, NULL),
(NULL, 8, 2 ),
( 8 , 3, NULL),
(NULL, 5, 5 );
-- DDL and sample data population, end
SELECT ID, Col1, Col2, Col3
, x.value('sum(/root/*/text())', 'INT') AS Summary
FROM #tbl
CROSS APPLY (SELECT Col1, Col2, Col3 FOR XML PATH(''), TYPE, ROOT('root')) AS t(x);
SQL #2
Based on the #DaleK's advice, a most common solution is below.
SELECT *
, Summary = COALESCE(Col1,0) + COALESCE(Col2,0) + COALESCE(Col3,0)
FROM #tbl;
SQL #3
A generic way tailored towards Col1, Col2, ..., ColN scenario.
SELECT ID, Col1, Col2, Col3
, x.value('sum(/root/*[not(local-name()="ID")]/text())', 'INT') AS Summary
FROM #tbl AS p
CROSS APPLY (SELECT * FROM #tbl AS c
WHERE c.ID = p.ID
FOR XML PATH(''), TYPE, ROOT('root')) AS t(x);
Output
+----+------+------+------+---------+
| ID | Col1 | Col2 | Col3 | Summary |
+----+------+------+------+---------+
| 1 | 4 | 9 | NULL | 13 |
| 2 | NULL | 8 | 2 | 10 |
| 3 | 8 | 3 | NULL | 11 |
| 4 | NULL | 5 | 5 | 10 |
+----+------+------+------+---------+
A computed column is often easier, if you want that calculation to always be available to anyone who queries the table:
ALTER TABLE YourTable
ADD COLUMN SumCol AS ISNULL(Col1, 0) + ISNULL(Col2, 0) + ISNULL(Col3, 0);

SQL Server - Select if one of all columns are unique

I want to select if one row where multiple columns are the same. For example:
col1 col2 col3 col4
a b 1 2
b b 1 2
a c 1 2
b b 1 3
a c 2 1
Condition: Select only if values of columns (col1, col2, col3) are different from other rows and value of col4 is max of rows which are the same.
For example expected Output is:
a b 1 2
b b 1 3
a c 1 2
a c 2 1
Yes possible, just use group by with max aggregation as
with tab(col1,col2,col3,col4) as
(
select 'a','b',1,2 union all
select 'b','b',1,2 union all
select 'a','c',1,2 union all
select 'b','b',1,3 union all
select 'a','c',2,1
)
select col1, col2, col3, max(col4) as col4
from tab
group by col1, col2, col3;
col1 col2 col3 col4
a b 1 2
a c 1 2
a c 2 1
b b 1 3
Rextester Demo
Mandatory NOT EXISTS solution... your condition written as a not exist query:
DECLARE #t TABLE (col1 varchar(100), col2 varchar(100), col3 int, col4 int);
INSERT INTO #t VALUES
('a', 'b', 1, 2),
('a', 'c', 1, 2),
('a', 'c', 2, 1),
('b', 'b', 1, 2),
('b', 'b', 1, 3);
SELECT *
FROM #t AS t
WHERE NOT EXISTS (
SELECT 1
FROM #t AS dup
WHERE dup.col1 = t.col1
AND dup.col2 = t.col2
AND dup.col3 = t.col3
AND dup.col4 > t.col4 -- outer row has smaller col4
)
Demo on DB Fiddle

Get Top N row from each set from table with 4 column in SQL Server

Assume I have a table with 4 columns:
Col1 Col2 Col3 Col4
My initial query is :
SELECT Col1, Col2, Col3, Col4
FROM myTable
ORDER BY Col1, Col2, Col3 DESC, Col4
My desired result is all 4 columns, but with this condition that Top N Col3 different row when Col1, Col2 is equal.
Example with N=2 :
Table sample data:
Col1 Col2 Col3 Col4
---------------------
1 a 2000 s
1 a 2002 c
1 a 2001 b
2 b 1998 s
2 b 2002 c
2 b 2000 b
3 c 2000 b
1 f 1998 n
1 g 1999 e
Desired result:
1 a 2002 c
1 a 2001 b
1 f 1998 n
1 g 1999 e
2 b 2002 c
2 b 2000 b
3 c 2000 b
In another description, when (col1, col2) is repeated in multiple records, just export top N rows of those records when order by Col3 descending.
Can I do this with SQL script, without hard coding?
declare #t table (Col1 int, Col2 char, Col3 int, Col4 char);
insert into #t values
(1, 'a', 2000, 's'),
(1, 'a', 2002, 'c'),
(1, 'a', 2001, 'b'),
(2, 'b', 1998, 's'),
(2, 'b', 2002, 'c'),
(2, 'b', 2000, 'b'),
(3, 'c', 2000, 'b'),
(1, 'f', 1998, 'n'),
(1, 'g', 1999, 'e');
declare #N int = 2; -- number per "top"
with cte as
(
select *,
row_number() over(partition by col1, col2 order by col3 desc) as rn
from #t
)
select *
from cte c
where rn <= #N;
I think below code was as expected
declare #tab table (Col1 int, Col2 char(1), Col3 int, Col4 char(1))
declare #N int
insert into #tab
select 1, 'a' , 2000, 's'
union all
select 1 , 'a' , 2002 , 'c'
union all
select 1 , 'a' , 2001 , 'b'
union all
select 2 , 'b' , 1998 , 's'
union all
select 2 , 'b' , 2002 ,'c'
union all
select 2 , 'b' , 2000 ,'b'
union all
select 3 , 'c' , 2000 ,'b'
union all
select 1 , 'f' , 1998 ,'n'
union all
select 1 , 'g' , 1999 ,'e'
;with tab as
(
select ROW_NUMBER() over(partition by t.col1,t.col2 order by t.col3 desc) as row,t.*
from #tab t
)
select Col1,Col2,Col3,Col4
from tab
where row < 3
output
Col1 Col2 Col3 Col4
1 a 2002 c
1 a 2001 b
1 f 1998 n
1 g 1999 e
2 b 2002 c
2 b 2000 b
3 c 2000 b
METHOD 1- FOR MSSQL
http://sqlfiddle.com/#!6/4bda39/6
with a as (
select ROW_NUMBER() over(partition by t.col1,t.col2 order by t.col3 desc) as row,t.*
from myTable as t)
select * from a where a.row <= 2
Replace a.row <= 2 (2 with your N)
METHOD 2- FOR MYSQL
http://sqlfiddle.com/#!9/79e81a/63
SELECT myTable.Col1, myTable.Col2, myTable.Col3, myTable.Col4
FROM (
Select Col1 as Col1, Col2 as Col2, count(Col1) as cc, AVG(Col3) as aa
From myTable
group by Col1, Col2) as tt
join myTable on myTable.Col1 = tt.Col1 and myTable.Col2 = tt.Col2
where myTable.Col3 >= tt.aa
Order by Col1 ,Col2 ,Col3 Desc,Col4
METHOD 3- FOR MYSQL
http://sqlfiddle.com/#!9/79e81a/79
SELECT * FROM (
SELECT CASE Col1
WHEN #Col1 THEN
CASE Col2
WHEN #Col2 THEN #curRow := #curRow + 1
ELSE #curRow := 1
END
ELSE #curRow :=1
END AS rank,
#Col1 := Col1 AS Col1,
#Col2 := Col2 AS Col2,
Col3, Col4
FROM myTable p
JOIN (SELECT #curRow := 0, #Col1 := 0, #Col2 := '') r
ORDER BY Col1, Col2, Col3 DESC) as tt
WHERE tt.rank <= 2
Replace tt.rank <= 2 replace 2 by your desired index

Query For Hierarchy Order In SQL

My Actual Table :
--------------------------------------------------
Col1 | Col2 | Col3 |
--------------------------------------------------
1 A 1
6 F 2
3 C 4
2 B 1
5 E 3
4 D 2
Expected Result :
------------------
|Columns Should Be|
------------------
A B F D C E
I need SQL query for this hierarchical logic.I have to get resultant logic using col 1 and col3 .Kindly help me out for this query.
I've just read your replies, I believe this is what you're after;
CREATE TABLE #TempData (Col1 int, Col2 varchar(1), Col3 int)
INSERT INTO #TempData (Col1, Col2, Col3)
VALUES
('1','A','1')
,('6','F','4')
,('6','C','2')
,('2','B','1')
,('5','E','3')
,('4','D','5')
SELECT
Col2
FROM #TempData
GROUP BY Col2
ORDER BY SUM(Col1)+SUM(Col3)
DROP TABLE #TempData
declare #table table (col1 int, col2 varchar(1), col3 int)
insert into #table (col1,col3)
values
(1, 1),
(6, 4),
(3, 2),
(2, 1),
(5, 3),
(4, 2)
/*
Col1 | Col2 | Col3 |
--------------------------------------------------
1 A 1
6 F 4
3 C 2
2 B 1
5 E 3
4 D 5
*/
select col1,
case
when col1 > col3 then char(col1 + 64)
else char(col3 + 64)
end as col2,
col3
from #table
in Sql server you may try this,
declare #t table (Col1 int, Col2 varchar(1), Col3 int)
INSERT INTO #t (Col1, Col2, Col3)
VALUES
('1','A','1')
,('6','F','2')
,('3','C','4')
,('2','B','1')
,('5','E','3')
,('4','D','2')
declare #str as varchar(100)=''
;with t as(select top 1 col1,col2,col3 from #t union all select t1.col1, t1.col2,t1.col3 from #t t1,t
where (t1.Col1!=t.Col1 and t1.Col3=t.Col1) )
select #str=#str+' '+col2 from t
select #str as col