How to delete only recode from table? - sql

I have one table in my database
Id Name
-------------------------
1 1 a
2 1 a
3 1 a
4 2 b
5 2 b
6 2 b
This my database table it's has 6 rows and 2 columns Id and Name
In this table field Id is not a primary key and i want to delete 2 number row from my by id field table
After Delete 2 row of table i want output like this
Id Name
-------------------------
1 1 a
3 1 a
4 2 b
5 2 b
6 2 b
Is it possible?

Your ID should be unique but here is the sql to delete all IDs that are 2.
Delete FROM table WHERE table.Id=2;
Replace 'table' with your table name.
Edit:
It appears like you want to delete the second result. I don't know why but here is the sql:
with rn AS
(
SELECT *, rn = ROW_NUMBER() OVER (ORDER BY (SELECT 0))
FROM table
)
DELETE
FROM rn
WHERE rn = 2

There must be some criteria in a table by which you could identify its rows. That is the primary key. How do know that the order of the rows stays the same? Your table is not even sortable, I mean you can't be sure that the same SELECT statement returns rows in the same order.
That's why I'd answer that you CAN'T delete only and exactly record number two, cause you have no order in your table. And one SELECT would result in different rows on the 2nd position.
If the Id field must have such values, probably you could add a surrogate primary key.

Related

Own id for every unique name in the table?

Is it possible to make a table that has like auto-incrementing id's for every unique name that I make in the table?
For example:
ID NAME_ID NAME
----------------------
1 1 John
2 1 John
3 1 John
4 2 Mary
5 2 Mary
6 3 Sarah
7 4 Lucas
and so on.
Use the window function rank() to get a unique id per name. Or dense_rank() to get the same without gaps:
SELECT id, dense_rank() OVER (ORDER BY name) AS name_id, name
FROM tbl;
I would advise not to write that redundant information to your table. You can generate that number on the fly. Or you shouldn't store name redundantly in that table, name would typically live in another table, with name_id as PRIMARY KEY.
Then you have a "names" table and run "SELECT or INSERT" there to get a unique name_id for every new entry in the main table. See:
Is SELECT or INSERT in a function prone to race conditions?
First add the column to the table.
ALTER TABLE yourtable
ADD [UID] INT NULL;
``
ALTER TABLE yourtable
ADD constraint fk_yourtable_uid_id foreign key ([UID]) references yourtable([Serial]);
Then you can update the UID with the minimum Serial ID per Name.
UPDATE t
SET [UID] = q.[UID]
FROM yourtable t
JOIN
(
SELECT Name, MIN([Serial]) AS [UID]
FROM yourtable
GROUP BY Name
) q ON q.Name = t.Name
WHERE (t.[UID] IS NULL OR t.[UID] != q.[UID]) -- Repeatability

Update a column in table which has a temp id with real id from the same column

I have come across a unique situation where I have a column called id which may have temp id until the final id comes through like:
id
temp id
1
null
2
1
6
null
7
6
I want a query that updates the table as :
id
temp id
2
null
2
1
7
null
7
6
basically once the id has a temp id associated with id, we just update all those temp ids with the real_id.
Any idea if this can be achieved. I try using case statements inside the updated table set but this doesn't work for me and also there are thousands of such records.
No issues with the temp id being redundant later because that id cannot repeat itself and thus it will not be a concern for analysis as we will use id only for analysis
You can use an update:
update t
set id = (select t2.id from t t2 where t2.tempid = t.id)
where t.tempid is null;

Snowflake SQL: concat values from multiple rows based on shared key

I have a table of values where there are a variable number of rows per each key value. I want to output a table that concats those row values together onto each distinct key value.
INPUT TABLE
KEY_ID
SOURCE_VAL
1
a
1
b
1
c
2
d
3
e
3
f
Target OUTPUT TABLE
KEY_ID
OUTPUT_VAL
1
a,b,c
2
d
3
e,f
What is the most efficient way to write this in Snowflake SQL?
It could be done with LISTAGG:
SELECT KEY_ID,
LISTAGG(SOURCE_VAL, ',') WITHIN GROUP(ORDER BY SOURCE_VAL) AS OUTPUT_VAL
FROM tab
GROUP BY KEY_ID

Update multiple rows based on unique values in another column in same table

I have a table with two columns. The table columns are name, and companyID, and they are in the [dbo].[Suppliers] table.
I need to update the CompanyID values ONLY for Unique Names.
UPDATE [dbo].[Suppliers]
SET CompanyId = 46
WHERE Name IN
(
SELECT DISTINCT Name
FROM [dbo].[Suppliers]
);
i.e.
Trying to get this
Name CompanyID
A 5
B 5
C 5
A 5
To look like:
Name CompanyID
A 6
B 6
C 6
A 5
Unfortunately, my query above is not doing the trick.
Appreciate any and all help. Thanks.
You can use a Common Table Expression to add a row number to each name, then update that CTE but specify only the first row for each name...
WITH
uniquely_identified AS
(
SELECT
ROW_NUMBER() OVER (PARTITION BY name ORDER BY companyID) AS name_row_id,
*
FROM
[dbo].[Suppliers]
)
UPDATE
uniquely_identified
SET
CompanyId = 46
WHERE
name_row_id = 1
;
Example: https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=4b5eba30b3bed71216ec678e9cffa6b9

Derive groups of records that match over multiple columns, but where some column values might be NULL

I would like an efficient means of deriving groups of matching records across multiple fields. Let's say I have the following table:
CREATE TABLE cust
(
id INT NOT NULL,
class VARCHAR(1) NULL,
cust_type VARCHAR(1) NULL,
terms VARCHAR(1) NULL
);
INSERT INTO cust
VALUES
(1,'A',NULL,'C'),
(2,NULL,'B','C'),
(3,'A','B',NULL),
(4,NULL,NULL,'C'),
(5,'D','E',NULL),
(6,'D',NULL,NULL);
What I am looking to get is the set of IDs for which matching values unify a set of records over the three fields (class, cust_type and terms), so that I can apply a unique ID to the group.
In the example, records 1-4 constitute one match group over the three fields, while records 5-6 form a separate match.
The following does the job:
SELECT
DISTINCT
a.id,
DENSE_RANK() OVER (ORDER BY max(b.class),max(b.cust_type),max(b.terms)) AS match_group
FROM cust AS a
INNER JOIN
cust AS b
ON
a.class = b.class
OR a.cust_type = b.cust_type
OR a.terms = b.terms
GROUP BY a.id
ORDER BY a.id
id match_group
-- -----------
1 1
2 1
3 1
4 1
5 2
6 2
**But, is there a better way?** Running this query on a table of over a million rows is painful...
As Graham pointed out in the comments, the above query doesn't satisfy the requirements if another record is added that would group all the records together.
The following values should be grouped together in one group:
INSERT INTO cust
VALUES
(1,'A',NULL,'C'),
(2,NULL,'B','C'),
(3,'A','B',NULL),
(4,NULL,NULL,'C'),
(5,'D','E',NULL),
(6,'D',NULL,NULL),
(7,'D','B','C');
Would yield:
id match_group
-- -----------
1 1
2 1
3 1
4 1
5 1
6 1
...because the class value of D groups records 5, 6 and 7. The terms value of C matches records 1, 2 and 4 to that group, and cust_type value B ( or class value A) pulls in record 3.
Hopefully that all makes sense.
I don't think you can do this with a (recursive) Select.
I did something similar (trying to identify unique households) using a temporary table & repeated updates using following logic:
For each class|cust_type|terms get the minimum id and update that temp table:
update temp
from
(
SELECT
class, -- similar for cust_type & terms
min(id) as min_id
from temp
group by class
) x
set id = min_id
where temp.class = x.class
and temp.id <> x.min_id
;
Repeat all three updates until none of them updates a row.