How to exclude rows in sql server insert statement? - sql

I have a statement like this
insert into A (id, nid)
(
select id, 100 as nid
from B
group by id
)
this works, but the problem is table A, has a primary key constraint on (id, nid), and some of the rows in the computed nested query, already exist in table A. How can I exclude them from being included in the nested query?
Thanks

You could use EXCEPT:
insert into A (id, nid)
select id, 100 as nid
from B
group by id
EXCEPT
SELECT id, nid
FROM A;

Just check if the rows exist...
insert into A (id, nid)
select id, 100 as nid
from B
WHERE NOT EXISTS (SELECT * FROM A WHERE A.id = B.id AND A.nid = 100)
group by id
PS: the parenthesis around your select are unnecessary

Add Where clause:
insert A (id, nid)
select id, 100 as nid
from B
Where Not exists (Select * from A
Where id = B.Id
and nid = 100)
group by id

Related

Group function in where IN clause

I have two tables having seq_no column:
select max(SEQ_NO) from final_prices;
select max(SEQ_NO) from price_loads;
I want to insert into a third table: archive_load from final_prices table on the condition that if the MAX(SEQ_NO) in final_prices exists in price_loads table
I am writing this query:
insert
into xx_label_prices_arc_temp
(select * from xx_label_final_prices where max (seq_no) in (select max(seq_no) from xx_label_price_loads));
It gives me the error:
group function is not allowed here
How can I insert based on this logic?
You can do:
insert into xx_label_prices_arc_temp
select *
from final_prices
where exists (
select 1 from price_loads where seq_no = (select max(seq_no) from final_prices)
)

Inserting unique value from another table

Tables: I have 3 tables
They are cust, new_cust, old_cust
all of them have 3 columns, they are id, username, name
each of them have possibilities to have same data as the others.
I would like to make "whole" table that consisting all of them but only the uniques.
I've Tried
Creating a dummy table
I've tried to create the dummy table called "Temp" table by
select *
into Temp
from cust
insert all table to dummy
Then I insert all of them into they Temp table
insert into temp
select * from new_cust
insert into temp
select * from old_cust
taking uniques using distinct
After they all merged I'm using distinct to only take the unique id value
select distinct(id), username, fullname
into Whole
from temp
it did decreasing some rows
Result
But after I move it to whole table I would like to put primary key on id but I got the message that there are some duplicate values. Is there any other way?
I am guessing that you want unique ids. And you want these prioritized by the tables in some order. If so, you can do this with union all and row_number():
select id, username, name
from (select c.*,
row_number() over (partition by id order by priority) as seqnum
from ((select id, username, name, 1 as priority
from new_cust
) union all
(select id, username, name, 2 as priority
from cust
) union all
(select id, username, name, 3 as priority
from old_cust
)
) c
) c
where seqnum = 1;
Try this:
insert into temp
select * from new_cust
UNION
select * from old_cust
Union will avoid the duplicate entries and you can then create a primary key on ID column
Try this below query...
WITH cte as (
SELECT id, username, NAME,
ROW_NUMBER() OVER (PARTITION BY t1.id ORDER BY t1.username, t1.name ) AS rn
FROM cust t1
LEFT JOIN new_cust t2 ON t1.Id = t2.Id
LEFT JOIN old_cust t3 ON t2.Id = t3.Id
)
SELECT id, username, NAME
FROM cte
WHERE rn = 1
Note:-
Put all the query inside a CTE(Common table expression)
with a new column(rn) that you will use to filter the results.
This new Column will produce ROW_NUMBER()....PARTITION BY username,name.....
But after I move it to whole table I would like to put primary key on
id but I got the message that there are some duplicate values.?
That's because You are trying to insert ID value from each of the tables to Whole table.
Just insert username and name and skip ID. ID is IDENTITY and it MUST be unique.
Run this on Your current Whole table to see if You have duplicated Id's:
select COUNT(ID), username
from whole
GROUP BY username
HAVING COUNT(ID) > 1
To get unique customers recreate table Whole and make ID col IDENTITY:
IF OBJECT_ID ('dbo.Whole') IS NOT NULL DROP TABLE dbo.Whole;
CREATE TABLE Whole (ID INT NOT NULL IDENTITY(1,1), Name varchar(max), Username varchar(max))
Insert values into Whole table:
INSERT INTO Whole
SELECT Name, Username FROM cust
UNION
SELECT Name, Username FROM new_cust
UNION
SELECT Name, Username FROM old_cust
Make ID col PK.
What does Unique mean for your row ?
If it is only the username, and you don't care about keeping the old ID values,
this will favor the new_cust data over the old_cust data.
SELECT
ID = ROW_NUMBER() OVER (ORDER BY all_temp.username)
, all_temp.*
INTO dbo.Temp
FROM
(
SELECT nc.username, nc.[name] FROM new_cust AS nc
UNION
SELECT oc.username, oc.[name]
FROM old_cust AS oc
WHERE oc.username NOT IN (SELECT nc1.username FROM new_cust AS nc1) --remove the where part if needed
) AS all_temp
ALTER TABLE dbo.Temp ALTER COLUMN ID INTEGER NOT NULL
ALTER TABLE dbo.Temp ADD PRIMARY KEY (ID)
If by Unique you mean both the username and name then just remove the where part in the union

Creating tables on-the-fly

It is often convenient in PosgreSQL to create "tables" on the fly so to refer to them, e.g.
with
selected_ids as (
select 1 as id
)
select *
from someTable
where id = (select id from selected_ids)
Is it impossible to provide multiple values as id this way? I found this answer that suggests using values for similar problem, but I have problem with translating it to the example below.
I would like to write subqueries such as
select 1 as id
union
select 2 as id
union
select 7 as id
or
select 1 as id, 'dog' as animal
union
select 7 as id, 'cat' as animal
in more condensed way, without repeating myself.
You can use arguments in the query alias:
with selected_ids(id) as (
values (1), (3), (5)
)
select *
from someTable
where id = any (select id from selected_ids)
You can also use join instead of a subquery, example:
create table some_table (id int, str text);
insert into some_table values
(1, 'alfa'),
(2, 'beta'),
(3, 'gamma');
with selected_ids(id) as (
values (1), (2)
)
select *
from some_table
join selected_ids
using(id);
id | str
----+------
1 | alfa
2 | beta
(2 rows)
You can pass id and animal field in WITH like this
with selected_ids(id,animal) as (
values (1,'dog'), (2,'cat'), (3,'elephant'),(4,'rat')--,..,.. etc
)
select *
from someTable
where id = any (select id from selected_ids)
You should use union and IN statement like this:
with
selected_ids as (
select 1 as id
union
select 2 as id
union
select 3 as id
....
)
select *
from someTable
where id in (select id from selected_ids)
after reviewing wingedpanther's idea and looking for it, you can use his idea IF those id's are continuously like this:
with
selected_ids as (
SELECT * FROM generate_series(Start,End) --(1,10) for example
)
select *
from someTable
where id in (select id from selected_ids)
If they are not continuously , the only way you can do that is by storing those ID's in a different table(maybe you have it already and if not insert it)
And then:
select *
from someTable
where id in (select id from OtherTable)

Counting repeated data

I'm trying to get maximum repeat of integer in table I tried many ways but could not make it work. The result I'm looking for is as:
"james";"108"
As this 108 when I concat of two fields loca+locb repeated two times but others did not I try below sqlfiddle link with sample table structure and the query I tried... sqlfiddle link
Query I tried is :
select * from (
select name,CONCAT(loca,locb),loca,locb
, row_number() over (partition by CONCAT(loca,locb) order by CONCAT(loca,locb) ) as att
from Table1
) tt
where att=1
please click here so you can see complete sample table and query I tried.
Edite: adding complete table structure and data:
CREATE TABLE Table1
(name varchar(50),loca int,locb int)
;
insert into Table1 values ('james',100,2);
insert into Table1 values ('james',100,3);
insert into Table1 values ('james',10,8);
insert into Table1 values ('james',10,8);
insert into Table1 values ('james',10,7);
insert into Table1 values ('james',10,6);
insert into Table1 values ('james',0,7);
insert into Table1 values ('james',10,0);
insert into Table1 values ('james',10);
insert into Table1 values ('james',10);
and what I'm looking for is to get (james,108) as that value is repeated two time in entire data, there is repetion of (james,10) but that have null value of loca so Zero value and Null value is to be ignored only those to be considered that have value in both(loca,locb).
SQL Fiddle
select distinct on (name) *
from (
select name, loca, locb, count(*) as total
from Table1
where loca is not null and locb is not null
group by 1,2,3
) s
order by name, total desc
WITH concat AS (
-- get concat values
SELECT name,concat(loca,locb) as merged
FROM table1 t1
WHERE t1.locb NOTNULL
AND t1.loca NOTNULL
), concat_count AS (
-- calculate count for concat values
SELECT name,merged,count(*) OVER (PARTITION BY name,merged) as merged_count
FROM concat
)
SELECT cc.name,cc.merged
FROM concat_count cc
WHERE cc.merged_count = (SELECT max(merged_count) FROM concat_count)
GROUP BY cc.name,cc.merged;
SqlFiddleDemo
select name,
newvalue
from (
select name,
CONCAT(loca,locb) newvalue,
COUNT(CONCAT(loca,locb)) as total,
row_number() over (order by COUNT(CONCAT(loca,locb)) desc) as att
from Table1
where loca is not null
and locb is not null
GROUP BY name, CONCAT(loca,locb)
) tt
where att=1

How to select distinct elements when they appear repeated in a table? (T-SQL)

Consider the following table:
create table temp
(
name int,
a int,
b int
)
insert into temp (name, a, b)
values (1, 2, 3)
insert into temp (name, a, b)
values (1, 4, 5)
insert into temp (name, a, b)
values (2, 6, 7)
I want to select *(all fields) with distinct [name]. In the case of two or more rows having the same [name], to choose whether to display the first (1, 2, 3) or the second row(1, 4, 5) the rule can be to choose the one with greater [b].
Can you point how must I write this stored procedure?
SELECT t.*
FROM temp t
INNER JOIN (
SELECT name, max(b) as b
FROM temp
GROUP BY name
) m
ON t.name = m.name
AND t.b = m.b
Not exactly fast on big tables, unless you have an index on name, b.
In MSSQL 2005 and above:
SELECT name, a, b
FROM (
SELECT temp.*, ROW_NUMBER() OVER (PARTITION BY name ORDER BY b DESC) AS rn
FROM temp
) t
WHERE rn = 1
Here is one way to do this
sql 2000 and up version
select t1.* from(
select name,max(B) as MaxB
from temp
group by name) t2
join temp t1 on t1.a = t2.MaxB
and t1.name = t2.name
SQL 2005 and up version
select name, a, b
from (
select m.*,
row_number() over (
partition by name
order by B desc) as rn
from temp m
) m2
where m2.rn = 1;
CREATE VIEW Max_B_From_Temp AS
SELECT name,Max(b) as b
FROM temp
GROUP BY name
SELECT temp.*
FROM temp INNER JOIN Max_B_From_Temp
ON
temp.name=Max_B_From_Temp.name and
temp.b=Max_B_From_Temp.b
Its not a stored procedure, but you can call the query from one.