SQL Server - updating distinct values - sql

I have 3 columns of data:
Column1 has duplicate values eg a a b b c c
Column2 has all NULL values
Column3 has other data that is not really important
I want to update Column2 with a value eh Hello but only for 1 instance of each value for column1. Eg, a = Hello but the 2nd instance of Hello is NULL, same with b c and so on.
I can find the distinct value by using this:
select distinct Column1
from TABLENAME
But when I try to update a different column it breaks. What is wrong (probably a lot!!) with this:
update TABLENAME
set Column2 = 'Hello'
where (select distinct Column1 from TABLENAME)

You can try to use ROW_NUMBER window function make row number then only update with row number is 1.
update t1
set Column2 = 'Hello'
FROM (
select *,ROW_NUMBER() OVER(PARTITION BY Column1 ORDER BY Column3) rn
from TABLENAME
) t1
where rn = 1
Results:
| Column1 | Column2 | Column3 |
|---------|---------|---------|
| a | Hello | 1 |
| a | (null) | 2 |
| b | Hello | 3 |
| b | (null) | 4 |
| c | Hello | 5 |
| c | (null) | 6 |

Assuming it is your unique index, use Column 3.
UPDATE tablename SET column2 = 'Hello' WHERE column3 IN
(SELECT column3 from TableName GROUP BY column1)

You could also update only the rows that have odd numbers in Column 3.
UPDATE tablename SET column2 = 'Hello' WHERE column3 % 2 != 0

You can also use CROSS APPLY and CTE (Common Table Expression) to achieve this:
;with CTE AS
(SELECT t.Column1, t.Column2
FROM (SELECT DISTINCT Column1
FROM TABLENAME) x
CROSS APPLY(SELECT TOP 1 *
FROM TABLENAME
WHERE column1 = x.column1) t)
UPDTATE CTE
SET Column2 = 'Hello'
SELECT * FROM TABLENAME

You could use a window function as
UPDATE TT
SET Col = B
FROM
(
SELECT Col, ROW_NUMBER() OVER(PARTITION BY Col ORDER BY Col) RN
FROM T
)TT INNER JOIN
(
VALUES (1, 'Hello'), (2, NULL)
) TVC (A, B)
ON TT.RN = TVC.A;
Results:
+-------+
| Col |
+-------+
| Hello |
| NULL |
| Hello |
| NULL |
| Hello |
| NULL |
+-------+
Or using a CASE expression as:
UPDATE TT
SET Col = CASE WHEN RN = 1 THEN 'Hello' END
FROM
(
SELECT Col, ROW_NUMBER() OVER(PARTITION BY Col ORDER BY Col) RN
FROM T
)TT;
Online Demo

Related

sql - Only want rows with NULL in column if it isn't defined somewhere else as well

I have a table with possible NULL values in a column. I need to return the NULL values, but only if it isn't also defined somewhere else. Below, I want row F, but I do not want row B. We have some automation that attempts something but also has a fail over. We need to identify when both tries fail.
Column 1 | Column 2
A | 1
B | 1
B | null
C | 2
C | 1
D | 1
E | 2
F | null
F | null
G | 2
Simply do aggregation :
select col1, null as col2
from table t
group by col1
having max(col2) is null;
You can use not exists:
select t.*
from mytable t
where not exists (
select 1
from mytable t1
where t1.column1 = t.column1 and t1.column2 is not null
)
Or you can use window functions:
select column1, column2
from (
select t.*, max(column2) over(partition by column1) max_column2
from mytable t
) t
where max_column2 is null

SQL Partition By Function without aggregation

I have a table with data like the following:
Column1 | Column2 | Column3 | Value
SQ03 | D | 1000040 | 1000
SQ03 | | 1000040 | 1000
SQ03 | | 1000050 | 2000
SQ03 | | 1000060 | 3000
SQ03 | L | 1000060 | 3000
SQ03 | D | 1000060 | 3000
What I need to do is to get a single value based on column3. Is a value in column3 is unique, I need to get that value. But if there are duplicates in Column3, I need to get the value where Column2 is not null. But like in the example that I showed in above, there are values for Column3 where Column2 is marked more than once, in these cases I need to get only one of these values, doesn't matter what.
So I thought on flagging which line I would need with the following solution:
select *, CASE
WHEN "Column2" != ' '
THEN 'X'
WHEN "Column2" = ' ' AND row_number() over(PARTITION BY "Column3" ORDER BY "Column2" DESC, "Column3") = 1
THEN 'X'
ELSE 'O'
END AS "FLAG" from DUMMY
WHERE "Column1" = 'SQ03'
But the problem with this solution is that it's aggregating the value from Column3. Like, it sums the values where Column3 has duplicates.
Can anyone help me with a solution where I don't get the values aggregated?
EDIT:
My expected output would be this:
Column1 | Column2 | Column3 | Value
SQ03 | D | 1000040 | 1000
SQ03 | | 1000050 | 2000
SQ03 | L | 1000060 | 3000
You can use a subquery to generate row numbers for each Column3 value (ordered by Column2 DESC to make NULL values come last), and then select the rows which have row_number = 1:
SELECT Column1, Column2, Column3, Value
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY Column3 ORDER BY Column2 DESC) AS rn
FROM DUMMY
WHERE Column1 = 'SQ03'
) D
WHERE rn = 1
Alternatively you can use a CTE:
WITH CTE AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY Column3 ORDER BY Column2 DESC) AS rn
FROM DUMMY
WHERE Column1 = 'SQ03'
)
SELECT Column1, Column2, Column3, Value
FROM CTE
WHERE rn = 1
Output for both queries:
Column1 Column2 Column3 Value
SQ03 D 1000040 1000
SQ03 (null) 1000050 2000
SQ03 L 1000060 3000
Demo on SQLFiddle
I think an aggregation function (as a window function) does what you want:
select t.*,
max(column3) over (partition by column1)
from t;

SQL code to get next variable in table with different value

I need to find a way in SQL Server 2014 Management Studios to find the next unique value in a column that shares the value of a different column.
So for example below I would want my results to be
Column 1 - A
Column 2 - 1
Column 3 - 4
As that is the first time that A has unique values in column 2 and 3
Column1 | Column2 | Column3
---------+---------+---------
| A | X | 1 |
| A | X | 2 |
| B | Y | 3 |
| A | Z | 4 |
Query:
SELECT
Column1,
LEAD(Column3) OVER (PARTITION BY Column2 ORDER BY Column3) AS FindValue
FROM
Table
If I understand it correctly I would try something like this:
-- first we find minimum values for column1, column2 variations
WITH min_values AS (
SELECT
column1,
column2,
min(column3) AS min_value
FROM
table
GROUP BY 1,2
)
-- then we find bottom 2 values for column1
,bottom_2 AS (
SELECT
column1,
min_value,
row_number() OVER (PARTITION BY column1 ORDER BY min_value ASC) AS rn
FROM
min_values
)
-- THEN we JOIN results INTO single record
SELECT
b1.column1, b2.min_value, b1.min_value
FROM
bottom_2 b1
JOIN
bottom_2 b2 ON b1.column1 = b2.column1 AND b2.rn < b1.rn
WHERE b1.rn <= 2
I just checked comments above and would like to add some notes.
If you want to find next value ordered by column2 then you have to change order by from min_value to column2 in row_number() line. Otherwise, if you are looking for next inserted value then you need a timestamp or some kind of id.

SQL rank/dense_rank and how to query/calculate with the result

So I have a table where it dense_ranks my rows.
Here is the table:
COL1 | COL2 | COL3 | DENSE_RANK |
a | b | c | 1 |
a | s | r | 1 |
a | w | f | 1 |
b | b | c | 2 |
c | f | r | 3 |
c | q | d | 3 |
So now I want to select any rows where the rank was only represented once, so the 2 is all alone, but not the 1 or 3. I want to select all the rows where this occurs, but how do I do that?
Some ideas:
-COUNT DISTINCT (RANK())
-COUNT RANK()
but neither of those are working, any ideas? please and thank you!
happy hacking
actual code:
SELECT events.event_type AS "event",
DENSE_RANK() OVER (ORDER BY bw_user_event.pad_id) as rank
FROM user_event
WHERE (software_events.software_id = '8' OR software_events.software_id = '14')
AND (software_events.event_type = 'install')
WITH Dense_ranked_table as (
-- Your select query that generates the table with dense ranks
)
SELECT DENSE_RANK
FROM Dense_ranked_table
GROUP BY DENSE_RANK
HAVING COUNT(DENSE_RANK) = 1;
I don't have SQL Server to test this. So please let me know whether this works or not.
I would think you can add a COUNT(*) OVER (PARTITION BY XXXXX) where XXXXX is what you include in your dense rank.
Then wrap this in a Common Table Expression and select where your new Count is = 1.
Something like this fiddler:
http://sqlfiddle.com/#!6/ae774/1
Code included here as well:
CREATE TABLE T
(
COL1 CHAR,
COL2 CHAR,
COL3 CHAR
);
INSERT INTO T
VALUES
('a','b','c'),
('a','s','r'),
('a','w','f'),
('b','b','c'),
('c','f','r'),
('c','q','d');
WITH CTE AS (
SELECT COL1 ,
COL2 ,
COL3,
DENSE_RANK() OVER (ORDER BY COL1) AS DR,
COUNT(*) OVER (PARTITION BY COL1) AS C
FROM dbo.T AS t
)
SELECT COL1, COL2, COL3, DR
FROM CTE
WHERE C = 1
Would return just the
b, b, c, 2
row from your test data.

Show complete row where one column is duplicate

I can't seem to know how to find something on this.
Here is my example which shows me just the duplicate column:
select column1,COUNT(column1)
from table
where column1> 0
GROUP BY column1
HAVING COUNT(column1) > 1
OUTPUT:
----------------------------
column1 | (name not defined)
----------------------------
2134567 | 2
2881992 | 3
What I want is:
------------------------------------------------
column0 | column2 |column1 | (name not defined)
------------------------------------------------
1 | abc |2134567 | 2
2 | cde |2881992 | 3
How can I achieve this?
You need to join your query back to the table you want to pull in the additional data from
SELECT column0, column2, table.column1, columncount
FROM table
INNER JOIN (SELECT column1, COUNT(column1) columncount
FROM table
WHERE column1> 0
GROUP BY column1 HAVING COUNT(column1) > 1) t2 ON table.column1 = t2.column1
Try something like:
SELECT * FROM [Tanle1]
WHERE Column0 IN
(SELECT Column0 FROM [Table1]
GROUP BY Column0
HAVING COUNT(Column0) > 1)