clear string in a column for specific rows - sql

i got a table which looks like this:
| col1 | ... | colx |
---------------------
| 1 | ... | dfd |
| 1 | ... | ajd |
| 1 | ... | aad |
| 2 | ... | azd |
| 2 | ... | iod |
| 3 | ... | asd |
| 3 | ... | aod |
| 3 | ... | wsd |
| 3 | ... | asi |
i want to update the table (or create a new table), so it looks like this:
| col1 | ... | colx |
---------------------
| 1 | ... | dfd |
| | ... | ajd |
| | ... | aad |
| 2 | ... | azd |
| | ... | iod |
| 3 | ... | asd |
| | ... | aod |
| | ... | wsd |
| | ... | asi |
any suggestions?

1.First add a new identity column to your table so we can order and update duplicate duplicate values to null:
alter table yourtable
add newcol int identity
2. If you want to update duplicate values in col1 to null then:
update yourtable
set col1 = null
where newcol not in (select min(newcol) from yourtable group by col1)
3.See your result:
select
*
from
yourtable
order by
newcol asc
You can not drop the identity column that was created but then you will loose your order..
If you don't want to update anything and just need a query
1.All you need is the following query AFTER you have created a new identity column on your table
select
*
from
yourtable
where
newcol in (select min(newcol) from yourtable group by col1)

Example
Select col1 = case when RN=1 then concat('',col1) else '' end
,other
,colx
From (
Select *
,RN = Row_Number() over (Partition By col1 order by colx)
From YourTable
) A
Order by A.Col1,RN
Returns

Something like this?
DECLARE #MyTable TABLE
(
COL1 int,
COLX nvarchar(50)
)
INSERT INTO #MyTable(COL1,COLX)
VALUES
( 1 ,'dfd'),
( 1 ,'ajd'),
( 1 ,'aad'),
( 2 ,'azd'),
( 2 ,'iod'),
( 3 ,'asd'),
( 3 ,'aod'),
( 3 ,'wsd'),
( 3 ,'asi')
select ISNULL(newcol,'')as col1,COLX from (
Select COLX,cast(Case when rn = 1 then COL1 else null end as nvarchar(50))
as NewCOL from (
Select * ,Row_number() over(Partition by col1 order by col1 ) as rn from
#MyTable
)x
)y
Result:

Related

Getting the last updated name

I am having a table having records like this:
+------+------+
| ID | name |
+------+------+
| 1 | A |
| 2 | B |
| 3 | C |
| 4 | A |
| 5 | B |
| 6 | A |
| 7 | A |
| 8 | A |
+------+------+
I need to get value of A after it was last updated from a different value, for example here it would be the row at ID 6.
Try this query (MySQL syntax):
select min(ID)
from records
where name = 'A'
and ID >=
(
select max(ID)
from records
where name <> 'A'
);
Illustration:
select * from records;
+------+------+
| ID | name |
+------+------+
| 1 | A |
| 2 | B |
| 3 | C |
| 4 | A |
| 5 | B |
| 6 | A |
| 7 | A |
| 8 | A |
+------+------+
-- run query:
+---------+
| min(ID) |
+---------+
| 6 |
+---------+
Using the Lag function...
SELECT Max([ID])
FROM (SELECT [name], [ID],
Lag([name]) OVER (ORDER BY [ID]) AS PrvVal
FROM tablename) tbl
WHERE [name] = 'A'
AND prvval <> 'A'
Online Demo: http://www.sqlfiddle.com/#!18/a55eb/2/0
If you want to get the whole row, you can do this...
SELECT Top 1 *
FROM (SELECT [name], [ID],
Lag([name]) OVER (ORDER BY [ID]) AS PrvVal
FROM tablename) tbl
WHERE [name] = 'A' AND prvval <> 'A'
ORDER BY [ID] DESC
Online Demo: http://www.sqlfiddle.com/#!18/a55eb/22/0
The ANSI SQL below uses a self-join on the previous id.
And the where-clause gets those with a name that's different from the previous.
select max(t1.ID) as ID
from YourTable as t1
left join YourTable as t2 on t1.ID = t2.ID+1
where (t1.name <> t2.name or t2.name is null)
and t1.name = 'A';
It should work on most RDBMS, including MS Sql Server.
Note that with the ID+1 that there's an assumption that are no gaps between the ID's.

Generate three rows in select query

I have following table
SELECT TableCode, Col1, Col2
FROM TableA
WHERE TableCode = 23
Result of Table:
TableCode | Col1 | Col1
23 | CustCode | QS
23 | CatCode | QS
After that i wrote one query on TableA which return following output
Query :
SELECT TableCode,x.ColCode,
x.ColumnName + '_' + CONVERT(VARCHAR(5), ROW_NUMBER() OVER (PARTITION BY X.COL ORDER BY X.COL)) [ColumnName],X.Values,
ROW_NUMBER() OVER (PARTITION BY X.COL ORDER BY X.COL) [RowNo]
FROM TableA a CROSS APPLY
(SELECT 1 ColCode,'ParaName' ColumnName,Col1 Values
UNION ALL
SELECT 2,'ParaSource',Col2
) x
WHERE TableCode = 23;
Result :
TableCode | ColCode | ColumnName | Values | RowNo
23 | 1 | ParaName_1 | CustCode | 1
23 | 1 | ParaName_2 | CatCode | 2
23 | 2 | ParaSource_1 | QS | 1
23 | 2 | ParaSource_2 | QS | 2
And i required following output:
Required Output :
TableCode | ColCode | ColumnName | Values | RowNo
23 | 1 | ParaName_1 | CustCode | 1
23 | 1 | ParaName_2 | CatCode | 2
23 | 1 | ParaName_3 | Null | 3
23 | 2 | ParaSource_1 | QS | 1
23 | 2 | ParaSource_2 | QS | 2
23 | 2 | ParaSource_3 | null | 3
Using a couple of common table expressions and row_number() along with the table value constructor (values (...),(...))
to cross join numbers 1, 2, and 3 then using a left join to return 3 rows per TableCode even when you do not have three rows in the source table.
;with numbered as (
select *, rn = row_number() over (order by (select 1))
from TableA
where TableCode = 23
)
, cte as (
select distinct tc.TableCode, a.Col1, a.Col2, v.rn
from numbered tc
cross join (values (1),(2),(3)) v (rn)
left join numbered a
on a.TableCode = tc.TableCode
and a.rn = v.rn
)
select
a.TableCode
, x.ColCode
, [ColumnName] = x.ColumnName + '_' + convert(varchar(5),a.rn)
, X.Value
,[RowNo] = a.rn
from cte a
cross apply (values (1,'ParaName',Col1),(2,'ParaSource',Col2))
as x(ColCode, ColumnName, Value)
order by ColCode, RowNo;
rextester demo: http://rextester.com/CJU8986
returns:
+-----------+---------+--------------+----------+-------+
| TableCode | ColCode | ColumnName | Value | RowNo |
+-----------+---------+--------------+----------+-------+
| 23 | 1 | ParaName_1 | CustCode | 1 |
| 23 | 1 | ParaName_2 | CatCode | 2 |
| 23 | 1 | ParaName_3 | NULL | 3 |
| 23 | 2 | ParaSource_1 | QS | 1 |
| 23 | 2 | ParaSource_2 | QS | 2 |
| 23 | 2 | ParaSource_3 | NULL | 3 |
+-----------+---------+--------------+----------+-------+
This would appear to do what you want:
SELECT TableCode, x.ColCode, v.*
FROM TableA a CROSS APPLY
(VALUES (1, 'ParaName-1', Col1, 1),
(2, 'ParaName-2', Col2, 2),
(3, 'ParaName-3', NULL, 2)
) v(ColCode, ColumnName, [Values], RowNo)
WHERE TableCode = 23;
I see no reason to use row_number() when you can just read in the correct values. Also, VALUES is a SQL keyword so it is a really bad column name.

How to display same values in set of columns once sql

I have a sql query result like this
id | subId | code | name | response
1 | 1 | abc | xyz | "Whatever"
1 | 1 | abc | xyz | "Whatever2"
1 | 2 | def | qrt | "Whatever3"
1 | 2 | def | qrt | "Whatever4"
I need to show first four columns(id,subid,code,name) once(on the basis of id and subid) where as response ids and response values as it is like
id | subId | code | name | responsevalue
1 | 1 | abc | xyz | "Whatever"
| "Whatever2"
1 | 2 | def | qrt | "Whatever3"
| "Whatever4"
Use ROW_NUMBER() to get a row number of record in the group and then for all not first records (row number <> 1) output NULLs with CASE statement.
WITH T1 AS
(
SELECT T.*,
ROW_NUMBER() OVER (PARTITION BY ID ORDER BY responseid ) as rn
FROM T
)
SELECT
CASE WHEN rn=1 THEN ID ELSE NULL END as ID,
CASE WHEN rn=1 THEN SubId ELSE NULL END as SubID,
CASE WHEN rn=1 THEN Code ELSE NULL END as Code,
CASE WHEN rn=1 THEN Name ELSE NULL END as Name,
responseId,
response_value
FROM T1
ORDER BY T1.id,rn

display records based on ranks and also delete duplicated data

i have a table like this
+------+------+------+------+
| col1 | col2 | col3 | rank |
+------+------+------+------+
| 1 | A | X | 4 |
| 2 | C | Y | 3 |
| 2 | C | Y | 3 |
| | A | X | 3 |
| 1 | B | Z | 2 |
+------+------+------+------+
(5 rows)
I need o/p like this
+------+------+------+------+
| col1 | col2 | col3 | rank |
+------+------+------+------+
| 1 | A | X | 4 |
| 2 | C | Y | 3 |
| 1 | B | Z | 2 |
+------+------+------+------+
so that I written query like below
select col1,col2,col3,rank,dense_rank() over(order by rank desc) from table1;
but its not giving proper o/p
try this !!
select a.col1,a.col2,a.col3,max(a.rank) as rank
from [dbo].[5] a join [dbo].[5] b
on a.col1=b.col1 group by a.col1,a.col2,a.col3
looks like you need aggregation with max():
select
col1,col2,col3,
max(rnk)
from table1
group by col1,col2,col3
If you could have different values of col1 for one combination of col2, col3, then distinct on is what you need:
select distinct on (col2, col3)
col1,col2,col3,
rnk
from table1
order by col2, col3, rnk desc
sql fiddle demo
The following should match what you are looking for:
select col1,col2,col3,rank,dense_rank() over(order by rank desc) from table1
WHERE col1 IS NOT NULL
GROUP BY 1, 2, 3, 4;
You can also use numeric aliases in your order by clause if you want one.

TSQL select the from two rows that has higher priority and is not null

I try to consolidate two rows of the same table whereas each row has a priority.
The value of interest is the value having priority 1 if it is not NULL; otherwise the value with priority 0.
An example data source could be:
| Id | GroupId | Priority | Col1 | Col2 | Col3 | ... | Coln |
-----------------------------------------------------------------
| 1 | 1 | 0 | NULL | 4711 | 3.41 | ... | f00 |
| 2 | 1 | 1 | NULL | NULL | 2.83 | ... | bar |
| 3 | 2 | 0 | NULL | 4711 | 3.41 | ... | f00 |
| 4 | 2 | 1 | 23 | NULL | 2.83 | ... | NULL |
and I want to have:
| GroupId | Col1 | Col2 | Col3 | ... | Coln |
-------------------------------------------------
| 1 | NULL | 4711 | 2.83 | ... | bar |
| 2 | 23 | 4711 | 2.83 | ... | f00 |
Is there a generic way in TSQL without the need to check each column explicitly?
SELECT
t1.GroupId,
ISNULL(t2.Col1, t1.Col1) as Col1,
ISNULL(t2.Col2, t1.Col2) as Col2,
ISNULL(t2.Col3, t1.Col3) as Col3,
...
ISNULL(t2.Coln, t1.Coln) as Coln
FROM mytable t1
JOIN mytable t2 ON t1.GroupId = t2.GroupId
WHERE
t1.Priority = 0 AND
t2.Priority = 1
Regards
I'll elaborate the ROW_NUMBER() solution that #KM suggested since IMO it's the best solution for this. (In CTE form for easier readability)
WITH cte AS (
SELECT
t1.GroupId,
t1.Col1,
t1.Col2,
ROW_NUMBER() OVER(PARTITION BY t1.GroupId ORDER BY ISNULL(GroupId ,-1) ) AS [row_id]
FROM
mytable t1
)
SELECT
*
FROM
cte
WHERE
row_id = 1
That will give you the row with the highest priority (according to your rules) for each GroupId in mytable.
ROW_NUMBER and RANK are two of my favorite TSQL tricks. http://msdn.microsoft.com/en-us/library/ms186734.aspx
edit: Another favorite of mine is PIVOT/UNPIVOT which you can use to transpose rows/columns which is another way of going about this type of problem. http://msdn.microsoft.com/en-us/library/ms177410.aspx
I think this would do what you are asking for without using isnull for every column
select
*
from
mytable t1
where
priority=(select max(priority) from mytable where groupid=t1.groupid group by groupid)