Insert into Teradata - sql

insert into tablex (a,b,c)
select distinct a,b,c
from tableA;
when I run select distinct statement alone it shows 6 rows.
When I run with insert it shows 0 rows inserted .
Is it a bug or AM I missing some thing.
#Teradata 13.10
masked original Query
INSERT INTO tablex
(SYSTEM_ID,START_DATE,END_DATE,CURRENT_FLAG )
SELECT DISTINCT
,s.SYSTEM_ID
,s.trans_DATE
,DATE '9999-12-31'
,'X'
FROM s JOIN cc
ON s.var_id=cc.var_id
WHERE s.sno = cc.sno
AND s.sno<>s.orino AND s.orino IS NOT NULL AND s.orino <> ''
AND cc.end_date=s.trans_date-1;

It's not a bug :-)
All six rows existed already in the target table and it's a SET table which automatically removes duplicate rows during an Insert/Select.

Related

Needing system defined function to select updated or unmatched new records from two tables

I am having a live data table in which the old values are placed,in a new table i am moving data from that live table to this one how to find updated or new records that are inserted or updated in new table with out using except,checksum(binary_checksum) and join ,i am looking for a solution using System Defined Function.
The requirement is interesting as the best solutions are to use EXCEPT or a FULL JOIN. What you are trying to do is what is referred to as an left anti semi join. Here's a good article about the topic.
Note this sample data and the solutions (note that my solution that does not use EXCEPT or a join is the last solution):
-- sample data
if object_id('tempdb.dbo.orig') is not null drop table dbo.orig;
if object_id('tempdb.dbo.new') is not null drop table dbo.new;
create table dbo.orig (someid int, col1 int, constraint uq_cl_orig unique (someid, col1));
create table dbo.new (someid int, col1 int, constraint uq_cl_new unique (someid, col1));
insert dbo.orig values (1,100),(2,110),(3,120),(4,2000)
insert dbo.new values (1,100),(2,110),(3,122),(5,999);
Here's the EXCEPT version
select someid
from
(
select * from dbo.new except
select * from dbo.orig
) n
union -- union "distict"
select someid
from
(
select * from dbo.orig except
select * from dbo.new
) o;
Here's a FULL JOIN Solution which will also tell you if the record was removed, changed or added:
select
someid = isnull(n.someid, o.someid),
[status] =
case
when count(isnull(n.someid, o.someid)) > 1 then 'changed'
when max(n.col1) is null then 'removed' else 'added'
end
from dbo.new n
full join dbo.orig o
on n.col1=o.col1 and n.someid = o.someid
where n.col1 is null or o.col1 is null
group by isnull(n.someid, o.someid);
But, because those efficient solutions are not an option - you will need to go with a NOT IN or NOT EXISTS subquery.... And because it has to be a function, I am encapsulating the logic into a function.
create function dbo.newOrChangedOrRemoved()
returns table as return
-- get the new records
select someid, [status] = 'new'
from dbo.new n
where n.someid not in (select someid from dbo.orig)
union all
-- get the removed records
select someid, 'removed'
from dbo.orig o
where o.someid not in (select someid from dbo.new)
union all
-- get the changed records
select someid, 'changed'
from dbo.orig o
where exists
(
select *
from dbo.new n
where o.someid = n.someid and o.col1 <> n.col1
);
Results:
someid status
----------- -------
5 new
4 removed
3 changed

If condition in SQL file vertica

I need to execute insertions for around 10 tables, before inserting I have to check for a condition, condition remains the same for each of the tables, instead of giving that condition within insert query, I wish I could give in if condition (a select query), if satisfied then execute insert statements, is there a way to give if condition in Vertica SQL file ? If condition is not satisfied I dont want to execute any of the insert queries.
If the condition is, for example, that you only insert the data on a Sunday, try this:
a) a test table:
CREATE LOCAL TEMPORARY TABLE input(id,name)
ON COMMIT PRESERVE ROWS AS
SELECT 42,'Arthur Dent'
UNION ALL SELECT 43,'Ford Prefect'
UNION ALL SELECT 44,'Tricia McMillan'
KSAFE 0;
From this table, select with a WHERE condition that tests whether it's sunday -- that's all, see here:
SELECT
*
FROM input
WHERE TRIM(TO_CHAR(CURRENT_DATE,'Day'))='Sunday'
;
id|name
42|Arthur Dent
43|Ford Prefect
44|Tricia McMillan
With a different value for the week day (I'm writing this on a Sunday...), you get this:
SELECT
*
FROM input
WHERE TRIM(TO_CHAR(CURRENT_DATE,'Day'))='Monday'
;
id|name
select succeeded; 0 rows fetched
I use this technique in SQL generating SQL to create a script or an empty file determining on circumstances, and then to call that script (full or empty), implementing a conditional SQL execution that way....
I know it is an old post, but i want to share what i recently solved my problem.
I need to insert in one table or another based on some condition. You first should have a field or value what will be your search condition.
create table tmp1 (
Col1 int null
,Col2 varchar(100) null
)
--Insert values
insert into tmp (Col1,Col2) Values
(1,'Text1')
,(2,'Text2')
--Insert into table001
insert into table001
select
t.field1
,t.field2
,......
from table1 t
inner join tmp t2
on t2.col1 = t.ColX
where 1 = case when t2.Col2 = 'Text1' then 1 else 0 end --Search condition; if 1<>0 then it doesn't do anything; otherwise insert.
--Insert into table002
insert into table002
select
t.field1
,t.field2
,......
from table2 t
inner join tmp t2
on t2.col1 = t.ColX
where 1 = case when t2.Col2 = 'Text2' then 1 else 0 end --Search condition; if 1<>0 then it doesn't do anything; otherwise insert.
Or you can use an UNION/UNION ALL based on this if it is the same working table.
Regards!

Deciphering SQL query

I am currently reviewing a query without access to the databases on which the query is performed. (It's not ideal but that's what I am tasked with). I am not a SQL expert and trying to identify what the below code does as I cannot run the query. It is reading from and writing to the same temp table (duplicating?). I don't know what the source of 'Y' is or what the end result is. Any help is appreciated. Thank you.
INSERT INTO #temp1
SELECT X.CURSTATUS ,X.GENDER ,Y.PACKAGE ,X.AGE ,1 AS factor1 ,1 AS factor2;
FROM #temp1 X WITH (NOLOCK) ,
( SELECT 'P1' AS PACKAGE UNION ALL SELECT 'P2' ) Y
WHERE X.PACKAGE = 'P5';
It is not really writing to the same table. It is "appending" rows to the same table. That is, existing data in the table is not affected.
What it is doing is adding rows for packages "P1" and "P2" for all "P5" packages. This adds the new rows to the table; the "P5" row remains.
For every row in #temp that has a PACKAGE value of "P5", the query is inserting two new rows with PACKAGE values of "P1" & "P2" respectivlly.
Reformatting the query and replacing obsolete syntax with modem syntax should make it easier to understand.
INSERT INTO #temp1 (CURSTATUS, GENDER, PACKAGE, AGE, factor1, factor2)
SELECT
X.CURSTATUS,
X.GENDER,
Y.PACKAGE,
X.AGE,
1 AS factor1,
1 AS factor2
FROM
#temp1 X
CROSS JOIN (
SELECT 'P1' AS PACKAGE
UNION ALL
SELECT 'P2'
) Y
WHERE
X.PACKAGE = 'P5';
INSERT INTO #temp1
-- this is where that data is being inserted into. It should BTW have columns explicitly defined, this format is a SQL antipattern
SELECT X.CURSTATUS ,X.GENDER ,Y.PACKAGE ,X.AGE ,1 AS factor1 ,1 AS factor2;
FROM #temp1 X WITH (NOLOCK) ,
-- this is selecting the current rows from #temp
( SELECT 'P1' AS PACKAGE UNION ALL SELECT 'P2' ) Y
--Y is a two record table with one column called package, since there is no specific join shown, it is a cross join - Again an antipattern, it is far better to explicitly use the Cross Join keywords to make it clear what is going on.
WHERE X.PACKAGE = 'P5';
-- this filters the records from #temp to grab only those where the record values is 'P5'. Since it cross joins to the Two record table Y, it takes the data in the other columns for the P% records and inserts new records for P1 and P2. If you have ten P5 records, this insert would insert 10 P1 records and 10 P2 records.

SQL query for selecting records where any of a given list of integers is between columnA and columnB

How can I get records from my table where any of a list of integers is in the range defined by columnA and columnB integer values?
I know about the IN operator when comparing against a column value instead of a range defined by a pair of columns.
For example: select * from mytable where mytable.colA in (1,3,5,6); would get all records where colA is either 1,3,5 or 6.
Is there anything like that for ranges? Or should I do like:
select * from mytable where 1 between mytable.colA and mytable.colb
OR
3 between mytable.colA and mytable.colb
OR
5 between mytable.colA and mytable.colb
OR
6 between mytable.colA and mytable.colb;
Maybe this way:
select distinct mytable.*
from mytable
join (select 1 nr union all select 3 union all select 5 union all select 6) n
on n.nr between mytable.colA and mytable.colb
Update:
Just tested on MariaDB (10.0.19) and a 1M-row indexed table.. Your original query is ways faster.
A common tactic is to set up a temporary table, and use that to join on your main table.
A simple way to set one up is like so:
DECLARE #TempList table (LookFor int not null)
INSERT #TempList (LookFor) values
(1)
,(3)
,(5)
,(6)
As this is a table, you can use querying logic to populate it.
Next up, join this into your target table. For your example above:
SELECT mt.*
from myTable mt
inner join #TempList tl
on tl.LookFor = mt.ColA
And, if I'm interpreting correctly, this might be what you're really looking for:
SELECT mt.*
from myTable mt
inner join #TempList tl
on tl.LookFor between mt.ColA and mt.ColB

How to make a range series in SQL

I have to improve a Stored Procedure, it uses a select query on a table as follows:
SELECT DISTINCT ProjectId FROM Project where Status ='P' Order by ProjectId
it give an output as follows:
1
2
3
7
8
11
12
13
I need to use these values in insert statement for another table as follow:
insert into Table values (othervalue, 1|1);
insert into Table values (othervalue, 2|2);
....
To decrease the number of inserts, we want to store as follows:
insert into Table values (othervalue, 1|3);
insert into Table values (othervalue, 7|8);
insert into Table values (othervalue, 11|13);
That is in range till the time there is no gap. I tried using CURSOR to loop through the resultset and have some logic to convert it and keep on inserting. But seems some error.
Can we do something in SELECTquery itself?
with t(a,en,bg) as
(
select a,case when [begin] is NULL then NULL else row_number() over(partition by [begin] order by a) end
,case when [end] is NULL then NULL else row_number() over(partition by [end] order by a) end
from (
select t.a, case when t1.a is NULL then 'end' else NULL end [end],
case when t2.a is NULL then 'begin' else NULL end [begin]
from Project as t left join Project as t1 on (t1.a=t.a+1 AND t.Status='P' AND t1.Status='P')
left join Project as t2 on (t2.a=t.a-1 AND t2.Status='P')
) as o )
select cast(t1.a as varchar)+'|'+cast(t.a as varchar) from t inner join t as t1 on t.en=t1.bg
This query will return you values from Project in '1|3' type.
It's not clear from your question whether you use plsql or sql-server. My solution will be work for MS SQL Server