SQL Server: multiple inserts in a single statement achievable? - sql

I'm using SQL Server. I have a table Users with 2 columns ID (string) and Info (string), and a table Positions with 2 columns PositionID (int) and Description (string).
I need to insert one record into table Links with 2 columns: UserID (string) and PositionID (int), for each record in table Positions.
Thus, given Users.ID = "JOE" and 3 records in Positions table with IDs 1 through 3, I need to insert 3 records into Links:
UserID | PositionID
-------+-----------
JOE | 1
JOE | 2
JOE | 3
Is this achievable with a single statement?

You can insert the result of a select statement. For example:
insert into links (user_id, position_id)
select 'JOE', position_id from positions

Adding to #The impaler's solution
insert into links (user_id, position_id)
select 'JOE', 1 from positions
union all select 'JOE', 2 from positions
union all select 'JOE', 3 from positions

Related

Keep IDs in sequential order after deleing a row [duplicate]

This question already has an answer here:
Renumbering sequence numbers
(1 answer)
Closed 6 months ago.
I have a Microsoft Access Database table, where i use the "Id" value in order to gather the information in that row.
Example:
Id Name Surname
1 Jim Smith
2 Luis Evans
3 Charles Holland
4 John Price
I have a Query which is used to delete one of the rows of this table, however when i delete a row in the table the Id values don't stay in a sequential order. For exmaple if i delete the id 2 row the table will look like this:
Id Name Surname
1 Jim Smith
3 Charles Holland
4 John Price
How do i make it so when I delete a row in the table the Ids stay in sequential order? Like this:
Id Name Surname
1 Jim Smith
2 Charles Holland
3 John Price
You can use a sub-query to get the "question number". Something like this:
SELECT Q.ID, Q.ForeName, Q.Surname,
(SELECT COUNT (*) FROM tblQuestion AS Q1 WHERE Q1.ID<=Q.ID) AS QuestionNo
FROM tblQuestion AS Q
ORDER BY Q.ID ASC;
This counts the number of records that have an ID less than or equal to the ID of the current record. So, in the table with 1 record deleted, ID 1 has 1 record (ID 1), ID 3 has two records (ID 1 and 3), and ID 4 has three records (ID 1, 3 and 4).
Note that Name is a reserved word, so you should use a different name for the field.
you can get temporary data like this
select ROW_NUMBER() over(order by Id) As Id,Name,Surname From TableData

PostgreSQL: how to delete duplicated rows grouped by the value of a column?

Given the following table, I need to delete every row corresponding to a certain "id" whenever all these rows are duplicated in a successive "id". Note that the deletion all rows for a specific "id" should happen only in case that every row between the two ids match (with the exception of the different "id" column).
id
name
subject
score
1
Ann
Maths
9
1
Ann
History
8
2
Ann
Maths
9
2
Ann
History
8
3
Ann
Maths
9
3
Ann
History
7
4
Bob
Maths
8
4
Bob
History
8
For this specific input, the updated output table should be:
id
name
subject
score
1
Ann
Maths
9
1
Ann
History
8
3
Ann
Maths
9
3
Ann
History
7
4
Bob
Maths
8
4
Bob
History
8
This because all records between id 1 and 2 are the exactly the same. This doesn't apply for "id" 1 and 3, as long as there's at least one row not in common between the two (id 1 has 8 in History while id 3 has 7 in the same subject).
So it is not as simple as deleting duplicated rows. Here's my attempt:
DELETE FROM table a
USING table b
WHERE a.name = b.name
AND a.subject = b.subject
AND a.score = b.score
AND a.ID < b.ID;
Can you help me?
You can first get all ids that shouldn't be deleted and then exclude them in the WHERE clause of the DELETE statement.
Step 1. In order to match unique ids that are not repeated for all rows, you can use PostgreSQL DISTINCT ON construct, that will allows you to get every row that is not duplicated on the fields "name", "subject", "score". Then retrieve these ids only once with a simple DISTINCT.
SELECT DISTINCT id
FROM (SELECT DISTINCT ON (name, subject, score) id
FROM tab
ORDER BY name, subject, score, id) ids_to_keep
Step 2. Hence you can build the DELETE statement using the NOT IN operator inside the WHERE clause:
DELETE FROM tab
WHERE id NOT IN (
SELECT DISTINCT id
FROM (SELECT DISTINCT ON (name, subject, score) id
FROM tab
ORDER BY name, subject, score, id) ids_to_keep
);
Check the demo here.

How to Insert the same records in same table with different value under Id column? (Note : ID is primary key autoincrement column )

Suppose i have table level as
ID name abbr countryid
1 None NN 11
2 Middle MD 33
3 Senior SN 33
4 Junior JN 22
No i want to insert the records of countryid 33 in same table with countryid 44 (Countryid 44 will be input parameter).But how to insert data under column ID? as Id is autoincrement?
INSERT INTO Master_LevelsGrades(Id, LevelName, LevelAbbr, CountryId)
(
select ?? ,LevelName,LevelAbbr,#NewCountryId
from Master_LevelsGrades where CountryId=33
)
Just leave it out:
insert into Master_LevelsGrades (LevelName, LevelAbbr, CountryId)
select LevelName, LevelAbbr, #NewCountryId
from Master_LevelsGrades
where CountryId = 33;
It will be set automagically.

distinct listagg in sql view

I have a table like this:
id name
1 ben
1 ben
2 charlie
2 dan
2 edgar
3 frank
and i want the following columns to be part of an existing view in sql developer:
id names
1 ben
2 charlie,dan,edgar
3 frank
I was able to generate the table (id, names) using listagg but i cant add it to the view (most popular error is invalid identifier).
please let me know if more information is needed.
thanks
Use a sub-query to first select only the DISTINCT rows before applying LISTAGG.
For example,
Setup
SQL> CREATE TABLE t
2 (id int, name varchar2(7));
Table created.
SQL>
SQL> INSERT ALL
2 INTO t (id, name)
3 VALUES (1, 'ben')
4 INTO t (id, name)
5 VALUES (1, 'ben')
6 INTO t (id, name)
7 VALUES (2, 'charlie')
8 INTO t (id, name)
9 VALUES (2, 'dan')
10 INTO t (id, name)
11 VALUES (2, 'edgar')
12 INTO t (id, name)
13 VALUES (3, 'frank')
14 SELECT * FROM dual;
6 rows created.
SQL>
Query
SQL> WITH DATA AS(
2 SELECT DISTINCT ID, NAME FROM t
3 )
4 SELECT ID,
5 listagg(NAME, ',') WITHIN GROUP (
6 ORDER BY ID) NAME
7 FROM DATA
8 GROUP BY ID;
ID NAME
---------- -----------------------------
1 ben
2 charlie,dan,edgar
3 frank
SQL>
Another way is to remove the duplicates from the aggregated values as answered here https://stackoverflow.com/a/27817597/3989608.
For example,
SQL> SELECT id,
2 RTRIM(REGEXP_REPLACE(listagg (name, ',') WITHIN GROUP (
3 ORDER BY id), '([^,]+)(,\1)+', '\1'), ',') name
4 FROM t
5 GROUP BY id;
ID NAME
---------- ---------------------------------------------
1 ben
2 charlie,dan,edgar
3 frank
SQL>

In SQL, find duplicates in one column with unique values for another column

So I have a table of aliases linked to record ids. I need to find duplicate aliases with unique record ids. To explain better:
ID Alias Record ID
1 000123 4
2 000123 4
3 000234 4
4 000123 6
5 000345 6
6 000345 7
The result of a query on this table should be something to the effect of
000123 4 6
000345 6 7
Indicating that both record 4 and 6 have an alias of 000123 and both record 6 and 7 have an alias of 000345.
I was looking into using GROUP BY but if I group by alias then I can't select record id and if I group by both alias and record id it will only return the first two rows in this example where both columns are duplicates. The only solution I've found, and it's a terrible one that crashed my server, is to do two different selects for all the data and then join them
ON [T_1].[ALIAS] = [T_2].[ALIAS] AND NOT [T_1].[RECORD_ID] = [T_2].[RECORD_ID]
Are there any solutions out there that would work better? As in, not crash my server when run on a few hundred thousand records?
It looks as if you have two requirements:
Identify all aliases that have more than one record id, and
List the record ids for these aliases horizontally.
The first is a lot easier to do than the second. Here's some SQL that ought to get you where you want with the first:
WITH A -- Get a list of unique combinations of Alias and [Record ID]
AS (
SELECT Distinct
Alias
, [Record ID]
FROM T1
)
, B -- Get a list of all those Alias values that have more than one [Record ID] associated
AS (
SELECT Alias
FROM A
GROUP BY
Alias
HAVING COUNT(*) > 1
)
SELECT A.Alias
, A.[Record ID]
FROM A
JOIN B
ON A.Alias = B.Alias
Now, as for the second. If you're satisfied with the data in this form:
Alias Record ID
000123 4
000123 6
000345 6
000345 7
... you can stop there. Otherwise, things get tricky.
The PIVOT command will not necessarily help you, because it's trying to solve a different problem than the one you have.
I am assuming that you can't necessarily predict how many duplicate Record ID values you have per Alias, and thus don't know how many columns you'll need.
If you have only two, then displaying each of them in a column becomes a relatively trivial exercise. If you have more, I'd urge you to consider whether the destination for these records (a report? A web page? Excel?) might be able to do a better job of displaying them horizontally than SQL Server can do in returning them arranged horizontally.
Perhaps what you want is just the min() and max() of RecordId:
select Alias, min(RecordID), max(RecordId)
from yourTable t
group by Alias
having min(RecordId) <> max(RecordId)
You can also count the number of distinct values, using count(distinct):
select Alias, count(distinct RecordId) as NumRecordIds, min(RecordID), max(RecordId)
from yourTable t
group by Alias
having count(DISTINCT RecordID) > 1;
This will give all repeated values:
select Alias, count(RecordId) as NumRecordIds,
from yourTable t
group by Alias
having count(RecordId) <> count(distinct RecordId);
I agree with Ann L's answer but would like to show how you can use window functions with CTE's as you may prefer the readability.
(Re: how to pivot horizontally, I again agree with Ann)
create temporary table things (
id serial primary key,
alias varchar,
record_id int
)
insert into things (alias, record_id) values
('000123', 4),
('000123', 4),
('000234', 4),
('000123', 6),
('000345', 6),
('000345', 7);
with
things_with_distinct_aliases_and_record_ids as (
select distinct on (alias, record_id)
id,
alias,
record_id
from things
),
things_with_unique_record_id_counts_per_alias as (
select *,
COUNT(*) OVER(PARTITION BY alias) as unique_record_ids_count
from things_with_distinct_aliases_and_record_ids
)
select * from things_with_unique_record_id_counts_per_alias
where unique_record_ids_count > 1
The first CTE gets all the unique alias/record id combinations. E.g.
id | alias | record_id
----+--------+-----------
1 | 000123 | 4
4 | 000123 | 6
3 | 000234 | 4
5 | 000345 | 6
6 | 000345 | 7
The second CTE simply creates a new column for the above and adds the count of record ids for each alias. This allows you to filter only those aliases which have more than one record id associated with them.
id | alias | record_id | unique_record_ids_count
----+--------+-----------+-------------------------
1 | 000123 | 4 | 2
4 | 000123 | 6 | 2
3 | 000234 | 4 | 1
5 | 000345 | 6 | 2
6 | 000345 | 7 | 2
SELECT A.CitationId,B.CitationId, A.CitationName, A.LoaderID, A.PrimaryReferenceLoaderID,B.SecondaryReference1LoaderID, A.SecondaryReference1LoaderID, A.SecondaryReference2LoaderID,
A.SecondaryReference3LoaderID, A.SecondaryReference4LoaderID, A.CreatedOn, A.LastUpdatedOn
FROM CitationMaster A, CitationMaster B
WHERE A.PrimaryReferenceLoaderID= B.SecondaryReference1LoaderID and Isnull(A.PrimaryReferenceLoaderID,'') != '' and Isnull(B.SecondaryReference1LoaderID,'') !=''