SQL No Dup (Distinct) on rows, but ignore one col - sql

For Example, Table with three cols and data
col1 col2 col3
10 20 30
40 50 60
40 50 80
Want to do a select where for the last two rows only returns one since col1 and col2 are the same.
select distinct will not work since col3 are different.
so output would be
10 20 30
40 50 xx (don't care)

As you only have one additional column you can just use an arbitrary MIN/MAX aggregate and GROUP BY
SELECT col1,
col2,
MAX(col3) AS col3
FROM YourTable
GROUP BY col1,
col2
More generally if your RDBMS supports analytic functions you can use
WITH T
AS (SELECT col1,
col2,
col3,
ROW_NUMBER() OVER (PARTITION BY col1, col2
ORDER BY col1, col2) AS RN
FROM YourTable)
SELECT col1,
col2,
col3
FROM T
WHERE RN = 1

I did this in SQL Server:
-- Setup test data:
declare #table table (
col1 int,
col2 int,
col3 int
)
insert into #table values (10, 20, 30)
insert into #table values (40, 50, 60)
insert into #table values (40, 50, 80)
-- Here's the query:
select col1, col2, cast(min(col3) as varchar(10)) as col3
from #table
group by col1, col2
having count(*) = 1
union all
select col1, col2, 'xx' as col3
from #table
group by col1, col2
having count(*) > 1
I suppose this assumes that you have no duplicate rows (where all fields are duplicates), otherwise you'd have a possibly incorrect 'xx'.

Related

How to do a select insert statement in sql with a changing value in the column for each row

Basically what I am trying to do in sql is find a way to do a select insert statement where all of the values in the other columns will stay the same but one of the columns value will increase by 1 for every row that is created. I am wondering if there is a way to do that in SQL.
You can use:
INSERT INTO table_name (col1, col2, col3)
SELECT col1, col2, col3 + 1
FROM table_name
Which, for the sample data:
CREATE TABLE table_name (col1, col2, col3) AS
SELECT LEVEL, LEVEL, LEVEL FROM DUAL CONNECT BY LEVEL <= 3;
Then, after the INSERT, the table contains:
COL1
COL2
COL3
1
1
1
2
2
2
3
3
3
1
1
2
2
2
3
3
3
4
And the col1 and col2 values of the inserted rows are the same and the col3 values have been incremented by 1.
If you want to increment the values by the number of rows being inserted then you can use:
INSERT INTO table_name (col1, col2, col3)
SELECT col1, col2, col3 + COUNT(*) OVER ()
FROM table_name
However
If you are attempting to add multiple rows and keep col3 with unique values then you should not use that method and should use a sequence.
If you have the table:
CREATE TABLE table_name (col1, col2, col3) AS
SELECT LEVEL, LEVEL, table_name__col3__seq.NEXTVAL FROM DUAL CONNECT BY LEVEL <= 3;
Then you can insert the rows using:
INSERT INTO table_name (col1, col2, col3)
SELECT col1, col2, table_name__col3__seq.NEXTVAL
FROM table_name
and col3 will be populated using the next sequence values.
db<>fiddle here

delete a row after comparing specific values with other rows in the same table

I have a table like this ( SQL SERVER )
col1 col2 col3 col4 col5
1 Goerge A B ++
2 Alex B B aa
2 Alex B B ++
now the second and the third rows have almost same values except in col5. in this case i want to delete one of them ( i want to be able to decide wich row from both of them i wanna delete ) like the one with value ++ so the table should look like this :
col1 col2 col3 col4 col5
1 Goerge A B ++
2 Alex B B aa
How can that be achieved?
Use CTE with ROW_NUMBER() to find (and delete) your duplicates
WITH CTE_Dup AS
(
SELECT *
, ROW_NUMBER OVER() PARTITION BY (Col1, Col2, Col3, Col4 ORDER BY Col5) RN
-- change ORDER BY criteria to make sure row you want to keep is 1st
FROM YourTable
)
DELETE --Try SELECT * to check before actually deleting
FROM CTE_Dup WHERE RN>1
It is not at all clear the logic you want here for determining which row is a "duplicate" but this example should show you a pretty straight forward way of handling this kind of thing.
declare #Something table
(
col1 int
, col2 varchar(10)
, col3 char(1)
, col4 char(1)
, col5 char(2)
)
insert #Something
values
(1, 'Goerge', 'A', 'B', '++')
, (2, 'Alex', 'B', 'B', 'aa')
, (2, 'Alex', 'B', 'B', '++')
;
with SortedValues as
(
select *
, ROW_NUMBER() over (partition by col1 order by col5 desc) as RowNum
from #Something
)
delete SortedValues
where RowNum > 1
select *
from #Something
You can try the below query. I grouped the columns and get the count of that and handled the conditions in the WHERE clause.
Query execution with the given sample data:
DECLARE #TestTable TABLE (col1 INT, col2 VARCHAR (20), col3 VARCHAR (20), col4 VARCHAR (20), col5 VARCHAR (20));
INSERT INTO #TestTable (col1, col2, col3, col4, col5) VALUES
(1, 'Goerge', 'A', 'B', '++'),
(2, 'Alex', 'B', 'B', 'aa'),
(2, 'Alex', 'B', 'B', '++');
SELECT * INTO #tmpResults FROM (
SELECT col1, col2, col3, col4, col5,
COUNT(*) OVER (PARTITION BY col1, col2, col3, col4 ORDER BY col1 ) AS CCnt
FROM #TestTable
) a
SELECT col1, col2, col3, col4, col5 FROM #tmpResults WHERE Ccnt = 1 AND Col5 = '++'
UNION
SELECT col1, col2, col3, col4, col5 FROM #tmpResults WHERE Ccnt > 1 AND Col5 <> '++';
DROP TABLE #tmpResults
Output:
col1 col2 col3 col4 col5
------------------------------------
1 Goerge A B ++
2 Alex B B aa

Merge rows into one row based on condition

I Have a table structure which similar to below
Create Table #Temp(Name varchar(10),Col1 int,Col2 int,Col3 int,Col4 int,Col5 int)
In this case table can have same name repeated but the other values to be different
So.
Sample values can be like
Insert Into #Temp
Values('ABC',1,0,0,1,1)
Insert Into #Temp
Values('ABC',1,0,1,1,0)
Insert Into #Temp
Values('ABC',1,0,1,1,0)
Insert Into #Temp
Values('DEF',0,0,0,1,0)
Insert Into #Temp
Values('DEF',1,0,1,1,1)
Insert Into #Temp
Values('DEF',1,1,0,1,1)
What I am trying to do here is select only one row for each name, but select the column with priority where it has value 1.
So the expected result in this case is
Name Col1 Col2 Col3 Col4 Col5
ABC 1 0 1 1 1
DEF 1 1 1 1 1
I have achieved it by doing something like below, which works absolutely fine. But is there any proper(easy) way of doing this.
SELECT Name,
(Select top 1 Col1
from #Temp T
Where T.Name=M.Name
Order By Col1 desc) as Col1,
(Select top 1 Col2
from #Temp T
Where T.Name=M.Name
Order By Col2 desc) as Col2,
(Select top 1 Col3
from #Temp T
Where T.Name=M.Name
Order By Col3 desc) as Col3,
(Select top 1 Col4
from #Temp T
Where T.Name=M.Name
Order By Col4 desc)as Col4,
(Select top 1 Col5
from #Temp T
Where T.Name=M.Name
Order By Col5 desc) as Col5
FROM #Temp M
Group By Name
It seems to me that you need to use MAX:
SELECT [Name],
MAX(Col1) Col1,
MAX(Col2) Col2,
MAX(Col3) Col3,
MAX(Col4) Col4,
MAX(Col5) Col5
FROM #Temp
GROUP BY [Name]
SELECT
Name,
Max(Col1) as Col1,
Max(Col2) as Col2,
Max(Col3) as Col3,
Max(Col4) as Col4,
Max(Col5) as Col5
FROM #Temp
GROUP BY Name

Sql insert select from – multiple rows with unique column id

I am trying to copy multiple records using one query using insert select from.
Insert into tab_A(colId, col1, col2, col3)
Select colId, col1, col2, col3 form tab_A
Where colId in ( 2,4,6)
Would it be possible to assign different colId for new entries? For example colid 2 should be replaced with 23, 4 with 24 and 6 with 25. How could I achieve it in a single query?
this would work
Insert into tab_A(colId, col1, col2, col3)
Select 23 , col1, col2, col3 form tab_A Where colId = 2 UNION ALL
Select 24 , col1, col2, col3 form tab_A Where colId = 4 UNION ALL
Select 25 , col1, col2, col3 form tab_A Where colId = 6
If you give some more info I could provide somthing more reusable. Should/is colId (be) an identity column?
EDIT
This would work in this very specialised case
Insert into tab_A(colId, col1, col2, col3)
Select ((colId - 4) * (-1)) + colId + 20 , col1, col2, col3
form tab_A Where colId IN (2, 4, 6)
The function newId = ((oldId - 4) * (-1)) + oldId + 20 is obviously specific to the stated problem.
EDIT2
I suspect somthing like this is more generic approach is appropriate.
DECLARE #MaxColID INT
BEGIN TRANSACTION
SELECT #MaxColID = MAX(ColID) FROM tab_A
INSERT tab_A(colId, col1, col2, col3)
SELECT row + #MaxColID, col1, col2, col3
FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY ColID) row, col1, col2, col3
FROM tab_A WHERE colID IN (2, 4, 6)
)
COMMIT
EDIT 3
If you think EDIT 2 is actually what you want then you really want to make ColID an IDENTITY column, then you could do this.
INSERT tab_A (col1, col2, col3)
SELECT col1, col2, col3 FROM tab_A WHERE colId IN (2, 4, 6)
I dont see col4 or col6 in your query, but is this what you want:
Insert into tab_A(colId, col1, col2, col3)
Select colId, col1, 23, col3 form tab_A
Where colId in ( 2,4,6)
have you just tried adding the disired difference to colId -
In your case, since you need to replace 2 by 23, difference is 21.
Insert into tab_A(colId, col1, col2, col3)
Select colId+21, col1, col2, col3
form tab_A Where colId in ( 2,4,6)
Note: I missed the part, that the differnce is not consistent in your case.
The proposed solution will work only if difference is same
There are a few options:
Add the new ID column to the original table and populate it with the new values before you do this insert, selecting the new ID column instead of the old. This would be the tidiest solution I think.
Alternative - Modify the ID value on the insert based on a rule e.g.
INSERT INTO tab_A(colID, col1, col2, col3)
SELECT colId + 20, col1, col2, col3
FROM tab_A
WHERE colID IN(2,4,6)
Last resort - Process the insert sequentially with a cursor, modifying the ID value each time.
You could also write case in the select. when 2 then 23 or whatever value.

Switching 1 row with few columns into 1 column with few rows in MS SQL SERVER

i've got 1 row with many columns:
col1|col2|col3|...
and i want to have 1 column with many rows, like that:
col1
col2
col3
..
UNPIVOT if you're using version 2005+
http://www.tsqltutorials.com/unpivot.php
If SQL Server 2000 or lower...
How to rotate a table in SQL Server: http://support.microsoft.com/kb/175574
Take a look at UNPIVOT:
CREATE TABLE Table1 (col1 INT, col2 INT, col3 INT, col4 INT);
INSERT INTO Table1 (col1, col2, col3, col4) VALUES (1,2,3,4);
SELECT col, value FROM Table1
UNPIVOT (value FOR col IN (col1, col2, col3, col4)) AS unpvt
Result:
col value
col1 1
col2 2
col3 3
col4 4
If you don't want to know which value came from which column, only select value:
SELECT value FROM Table1
UNPIVOT (value FOR col IN (col1, col2, col3, col4)) AS unpvt