"ORA-00928: missing SELECT keyword” - sql

I am getting "ORA-00928: missing SELECT keyword” error for following query:
insert into candidate_address_t ('ADDRESS_LINE1','ADDRESS_LINE2','CITY','ADDRESS_ID','ZIP','CREATED_BY','MODIFIED_BY','CREATED_DATE','MODIFIED_DATE','ACTIVE_INACTIVE_FLG','ADDRESS_TYPE_ID','CANDIDATE_ID','STATE_ID','GOOGLE_MAP_LINK','SOURCE_TYPE_ID','COUNTRY_TYPE_ID')
values ('test',null,'test','0000','H3X 2P3','9304','9304', sysdate,sysdate,1,'0000','0000','000',null,1,1);

insert into candidate_address_t (ADDRESS_LINE1
,ADDRESS_LINE2
,CITY
,ADDRESS_ID
,ZIP
,CREATED_BY
,MODIFIED_BY
,CREATED_DATE
,MODIFIED_DATE
,ACTIVE_INACTIVE_FLG
,ADDRESS_TYPE_ID
,CANDIDATE_ID
,STATE_ID
,GOOGLE_MAP_LINK
,SOURCE_TYPE_ID
,COUNTRY_TYPE_ID)
values ('test'
,null
,'test'
,'0000'
,'H3X 2P3'
,'9304'
,'9304'
,sysdate
,sysdate
,1
,'0000'
,'0000'
,'000'
,null
,1
,1);
Also, instead of explicitly inserting null into a column, simply omit the column from the list.
Also, you don't need the columns list if you supply a value for every column in the values list.

Related

How to insert multiple rows into SQL using an Array?

I want to insert multiple rows into a database if they don't already exist, swapping out one columns value for each insertion. Below is some pseudo code of the goal:
IF NOT EXISTS (SELECT [ChangeReason] FROM BudgetAndAuthorizationChangeReasons WHERE [ChangeReason]= ('Other','Scope Change'))
INSERT INTO [dbo].[BudgetAndAuthorizationChangeReasons]
([ChangeReason]
,[IsActive]
,[CreatedByUser]
,[CreatedOn]
,[LastUpdatedByUser]
,[LastUpdatedOn])
VALUES
( ('Other','Scope Change')
,'true'
,'system'
,GETDATE()
,null
,null)
GO
In other words, if a row with ChangeReason='Other' already exists, nothing will happen. If it does not exist, then it will be inserted with all the other values outlined as above (IsActive=true, etc). This will be repeated for each element in the array : ('Other','Scope Change')
EDIT:
I have written a stored procedure to take care of the dirty work for me. Is it possible to call this automatically for every element in the array? Or do I need X different exec statements?
IF EXISTS ( select * from sys.procedures where name='SafeInsert_BudgetAndAuthorizationChangeReasons') begin
DROP PROC SafeInsert_BudgetAndAuthorizationChangeReasons
end;
GO
create procedure SafeInsert_BudgetAndAuthorizationChangeReasons #Reason varchar(50)
as
begin
IF NOT EXISTS (SELECT [ChangeReason] FROM BudgetAndAuthorizationChangeReasons WHERE [ChangeReason]= #Reason)
INSERT INTO [dbo].[BudgetAndAuthorizationChangeReasons]
([ChangeReason]
,[IsActive]
,[CreatedByUser]
,[CreatedOn]
,[LastUpdatedByUser]
,[LastUpdatedOn])
VALUES
(#Reason
,'true'
,'system'
,GETDATE()
,null
,null);
end;
GO
exec SafeInsert_BudgetAndAuthorizationChangeReasons #Reason='Other';
-- goal: auto-exec for every element in ('Other','Scope Change')
SQL doesn't understand arrays, but you can list multiple insert values like below.
INSERT INTO [dbo].[BudgetAndAuthorizationChangeReasons]
([ChangeReason]
,[IsActive]
,[CreatedByUser]
,[CreatedOn]
,[LastUpdatedByUser]
,[LastUpdatedOn])
VALUES
('Other' , 'true', 'system', GETDATE(), null, null)
,('Scope Change' , 'true', 'system', GETDATE(), null, null)
You can create a pseudo-table using values like so:
select v.Id, v.Name from (values (1, 'Jason'), (2, 'Tony'), (3, 'Michelle')) v(Id, Name)
v is any alias you want to give it and you specify the names for the columns in parentheses. You can combine that with the MERGE statement to only insert those rows if they don't exist.
WITH SOURCE_CTE AS (
select ChangeReason, IsActive, CreatedByUser, CreatedOn, LastUpdatedByUser, LastUpdatedOn
from (values ('Other', 'true', 'system', getdate(), null, null),
('Scope Change', 'true', 'system', getdate(), null, null)
) tbl (ChangeReason, IsActive, CreatedByUser, CreatedOn, LastUpdatedByUser, LastUpdatedOn)
)
MERGE into dbo.BudgetAndAuthorizationChangeReasons as t
using SOURCE_CTE as s
on t.ChangeReason = s.ChangeReason
when not matched by target then
insert (
ChangeReason,
IsActive,
CreatedByUser,
CreatedOn,
LastUpdatedByUser,
LastUpdatedOn
)
values
(
s.ChangeReason,
s.IsActive,
s.CreatedByUser,
s.CreatedOn,
s.LastUpdatedByUser,
s.LastUpdatedOn
)
* Edit after stored procedure change *
I'm not sure where your data is coming from and how you're passing it. First it seemed like it was just in a sql script. I find things like above handy for config tables, putting a script in the database project post-deploy to make sure values exist.
If using stored procedures, why not just call the stored procedure for each value?
exec SafeInsert_BudgetAndAuthorizationChangeReasons #Reason='Other';
exec SafeInsert_BudgetAndAuthorizationChangeReasons #Reason='Scope Change';
You could create a UDTT and load that with values and pass it to your stored proc:
create type StringList as table (
value varchar(256)
);
Create Procedure SafeInsert_BudgetAndAuthorizationChangeReasons #Reasons StringList readonly
...
INSERT INTO [dbo].
[BudgetAndAuthorizationChangeReasons]
([ChangeReason]
,[IsActive]
,[CreatedByUser]
,[CreatedOn]
,[LastUpdatedByUser]
,[LastUpdatedOn])
(select 'Other','Scope Change',
,'true'
,'system'
,GETDATE()
,null
,null) where NOT EXISTS (SELECT
[ChangeReason] FROM
BudgetAndAuthorizationChangeReasons WHERE [ChangeReason] IN ('Other','Scope Change'))
or you can have a trigger before insert
Create Trigger name before insert
On
BudgetAndAuthorizationChangeReasons
For each row
As
IIF(SELECT COUNT(*) FROM (SELECT
[ChangeReason] FROM
BudgetAndAuthorizationChangeReasons
WHERE [ChangeReason] IN
('Other','Scope Change'))) >0)
THEN
INSERT......
END IF
END
or you can use a procedure
checkData(ChangeReason IN
BudgetAndAuthorizationChangeReasons.
ChangeReason%TYPE)
AS
IIF(SELECT COUNT(*) FROM
(SELECT
[ChangeReason] FROM
BudgetAndAuthorizationChangeReasons
WHERE [ChangeReason] IN
('Other','Scope Change'))) >0)
THEN
INSERT CHANGEREASON......
END IF
END
INSERT INTO [dbo].[BudgetAndAuthorizationChangeReasons] ([ChangeReason]
,[IsActive]
,[CreatedByUser]
,[CreatedOn]
,[LastUpdatedByUser]
,[LastUpdatedOn])
SELECT [ChangeReason],'true','system',getDate(),null,null
FROM BudgetAndAuthorizationChangeReasons
WHERE [ChangeReason]in ('Other','Scope Change')
[dbo].[BudgetAndAuthorizationChangeReasons] table should exist.
You struggle with the code because you struggle to define your goal. And that bleeds into those trying to help. Given a set of reasons, you simply want to all those that do not already exist in the table.
-- declare variables for demo
declare #rsn table (ChangeReason varchar(20) not null primary key,
IsActive varchar(5) not null, CreatedOn datetime not null);
-- add some "existing" data to table
insert #rsn (ChangeReason, IsActive, CreatedOn)
values ('Other', 'true', '20190801 13:01:01');
-- demonstrate the use of a table value constructor
with cte as (select * from (values ('Other'), ('Scope'), ('Change')) as x(rsn))
select * from cte;
-- use a transaction for testing just in case you actually use a real table
-- and not a table variable
begin tran;
merge into #rsn as target
using (values ('Other'), ('Scope'), ('Change')) as source(rsn)
on target.ChangeReason = source.rsn
when not matched by target then
insert (ChangeReason, IsActive, CreatedOn) values (rsn, 'true', getdate())
;
-- verify logic worked correctly
select * from #rsn;
rollback tran;
Here is fiddle to demonstrate. Notice that this makes use of table value constructor which is a very handy thing to know.

Creating new columns in Sql Server based on other columns

I have a table T :
CREATE TABLE T
(
id INT,
type VARCHAR(200),
type_value VARCHAR(10),
value VARCHAR(200)
);
INSERT INTO T VALUES (1, 'HomePhone', 'p1', '1234 ');
INSERT INTO T VALUES (1, 'HomePhone', 'p2', '5678 ');
INSERT INTO T VALUES (1, 'HomePhone', 'p3', '4567');
INSERT INTO T VALUES (1, 'WorkPhone', 'w1', '9007 ');
INSERT INTO T VALUES (2, 'Email', 'e1', 'abc#xyz.com ');
INSERT INTO T VALUES (2, 'Email', 'e1', 'efg#xyz.com');
INSERT INTO T VALUES (2, 'Email', 'e2', 'mno#xyz.com');
INSERT INTO T VALUES (3, 'WorkPhone', 'w1', '0100');
INSERT INTO T VALUES (3, 'WorkPhone', 'w2', '0110');
INSERT INTO T VALUES (4, 'OtherPhone', 'o1', '1010 ');
INSERT INTO T VALUES (4, 'OtherPhone', 'o1', '1110 ');
INSERT INTO T VALUES (4, 'OtherPhone', 'o1', '1011');
INSERT INTO T VALUES (4, 'HomePhone', 'p1', '2567 ');
I need to transform it into :
id primaryhomephone secondaryhomephone primaryemail secondaryemail Primaryworkphone secondaryworkphone primaryotherphone secondaryotherphone
----------------------------------------------------------------------------------------------------------------------------------------------------------------
1 1234 5678 null null 9007 null null null
2 null null abc#xyz.com efg#xyz.com null null null null
3 null null null null 0100 0110 null null
4 2567 null null null null null 1010 1011
Basically the field will be divided based on type_value. If there is two type_value for same id and type then first type will be primary and second type will be secondary.
For more than two type values for same id and type, discard the third one.
For more than two type values of same type(for example o1,o1) for id 4 first o1 will be primaryotherphone and second one will be secondaryprimaryphone.
Sorry if this question has been repeated before but somehow I can't solve it. Can anyone please help. Thanks a lot
You can use MAX/GROUP BY technique. PIVOT is quite complex for beginners, but I agree that the purpose of the PIVOT is the exactly what you need:
SELECT id
, MAX(CASE WHEN type_value = 'p1' THEN value END ) AS primaryhomephone
, MAX(CASE WHEN type_value = 'p2' THEN value END ) AS secondaryhomephone
, MAX(CASE WHEN type_value = 'p3' THEN value END ) AS thirdphone
, MAX(CASE WHEN type_value = 'w1' THEN value END ) AS workphone
, MAX(CASE WHEN type_value = 'w2' THEN value END ) AS secondaryworkphone
, MAX(CASE WHEN type_value = 'o2' THEN value END ) AS otherworkphone
, MAX(CASE WHEN type_value = 'e1' THEN value END ) AS primaryemail
, MAX(CASE WHEN type_value = 'e2' THEN value END ) AS secondaryemail
FROM T
GROUP BY id
;
You need to look after computed columns in SQL Server.
CREATE TABLE [dbo].T
(
...
[primaryhomephone] AS (CASE WHEN type_value = 'p1' THEN value ELSE NULL END)
)
Alternatively you can use Views:
CREATE VIEW dbo.vwT
AS
SELECT
id
,(CASE WHEN type_value = 'p1' THEN value ELSE NULL END as [primaryhomephone]
, (CASE WHEN type_value = 'p2' THEN value ELSE NULL END as [secondaryhomephone]
FROM dbo.T
You need to look into PIVOT Column presentation. You can use it in to ways, you can create new Table with your column and then use PIVOT Query to insert them there, or you can simply fetch at runtime. If there is lot of data and all other Programming interface are ready to upgrade then make new table, else just use query.
Here is the link for your reference: https://technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx

Merge causes too slow, how to optimize this query

How can I optimize this query. I am using merge to pull inserted id's
I have looked at execution plan. It was causing more cost on sort.
Is there any other way to do this instead of using merge. I have tried using BY TARGET. Still its slow. I want to get ride of this merge statement.
DECLARE #TEMP_STUDENT_DETAILS_ID AS TABLE (STUDENT_DETAILS_ID INT, SCHOOL_ID INT)
MERGE INTO DBO.STUDENT_DETAILS USING (
SELECT ISNULL(SUM(MARKS),0) AS MARKS, SCHOOL_ID
FROM DBO.OLD_STUDENT_DETAILS
WHERE SCHOOL_ID IS NOT NULL
GROUP BY SCHOOL_ID) SRC ON 1 = 0
WHEN NOT MATCHED BY TARGET THEN
INSERT (MARKS
,SCHOOL_ID
,CODE_ID
,CODE_VALUE
,CREATED_BY
,CREATED_DATE
,MODIFIED_BY
,MODIFIED_DATE)
VALUES (SRC.MARKS
,SRC.SCHOOL_ID
,101 --CODE_ID
,'ADA' --CODE_VALUE
,'Admin'
,GETDATE()
,'Admin'
,GETDATE())
OUTPUT INSERTED.STUDENT_DETAILS_ID, SRC.SCHOOL_ID INTO #TEMP_STUDENT_DETAILS_ID;
You can use the OUTPUT statement with an insert. https://learn.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql This is certainly a bit cleaner than a merge with a forced not matching.
INSERT DBO.STUDENT_DETAILS
( MARKS
,SCHOOL_ID
,CODE_ID
,CODE_VALUE
,CREATED_BY
,CREATED_DATE
,MODIFIED_BY
,MODIFIED_DATE
)
OUTPUT INSERTED.STUDENT_DETAILS_ID, INSERTED.SCHOOL_ID INTO #TEMP_STUDENT_DETAILS_ID
SELECT ISNULL(SUM(MARKS),0) AS MARKS
, SCHOOL_ID
,101 --CODE_ID
,'ADA' --CODE_VALUE
,'Admin'
,GETDATE()
,'Admin'
,GETDATE()
FROM DBO.OLD_STUDENT_DETAILS
WHERE SCHOOL_ID IS NOT NULL
GROUP BY SCHOOL_ID

Msg 102, Level 15, State 1, Line 1 Incorrect syntax near '('

I am trying to query to insert in a table and i keep getting this message:
The Query is:
INSERT INTO A_USER(PK,status,login_id,HASHBYTES('md5', password),fk_role,last_update_ts,last_update_by,created_by)
VALUES (2,1,'abc', 'abc',2,'3/15/2012 12:21:46 PM','abc','abc')
INSERT INTO EMP_USER(PK,status,login_id,password,fk_role,last_update_ts,last_update_by,created_by)
VALUES (2,1,HASHBYTES('md5', password),'abc','abc',2,'3/15/2012 12:21:46 PM','abc','abc')
insert statement works like that
insert into table (col1, col2) values (val1, val2)
Put HASHBYTES('md5', password) in the values part and name that column in the column part
Your issue is with this line HASHBYTES('md5', password), you want to use the HASHBYTES in the VALUES area of your INSERT.
INSERT INTO A_USER
(
PK
,status
,login_id
,[password] -- change to the name of your column.
,fk_role
,last_update_ts
,last_update_by
,created_by
)
VALUES
(
2
,1
, 'abc'
,HASHBYTES('md5', 'abc') -- place your password to be hashed where 'abc' is.
,2
,'3/15/2012 12:21:46 PM'
,'abc'
,'abc'
)

Ambiguity in Select Query

This is my test table:
CREATE TABLE [General].[Test]
(
[Name] NVARCHAR(20) NOT NULL,
[SSN] CHAR(10) NOT NULL,
CONSTRAINT [UK_Test_SSN]
UNIQUE NONCLUSTERED ([SSN]) WITH (IGNORE_DUP_KEY = OFF),
)
And I inserted some values:
INSERT INTO [General].[Test] ([SSN], [Name]) VALUES (N'901223476', N'Lol1');
INSERT INTO [General].[Test] ([SSN], [Name]) VALUES (N'2591830061', N'Lol2');
INSERT INTO [General].[Test] ([SSN], [Name]) VALUES (N'4431776273', N'Lol3');
INSERT INTO [General].[Test] ([SSN], [Name]) VALUES (N'987654321', N'Lol4');
INSERT INTO [General].[Test] ([SSN], [Name]) VALUES (N'123456789', N'Lol5');
INSERT INTO [General].[Test] ([SSN], [Name]) VALUES (N'0123456789', N'Lol6');
INSERT INTO [General].[Test] ([SSN], [Name]) VALUES (N'0012345678', N'Lol7');
INSERT INTO [General].[Test] ([SSN], [Name]) VALUES (N'123', N'Lol8');
And the first SELECT query:
SELECT
CASE
WHEN [T].[SSN] LIKE REPLICATE('[0-9]',10) THEN [T].[SSN]
ELSE 1000000000 + ROW_NUMBER() OVER(ORDER BY [T].[Name]) END AS [SSN]
FROM [General].[Test] AS [T];
GO
And the second query:
SELECT [T].[SSN] FROM [General].[Test] AS [T];
The ambiguity that I can't understand is about rows 6 and 7 whose [SSN] values start with 0
So for example about 6th row the first query returns 123456789 and second query return 0123456789, can anyone explain why? And I really need to get the real value of 0123456789 in the first query, what can I do?
You have two different datatypes being returned from your first column in the first query - in the first case, the CHAR(10) of the [SSN] is returned, in the ELSE case a large INT number. That's why SQL Server needs to convert one of the two datatypes to the other.
What you need to do, if you want to get back the CHAR(10), is to CAST the second expression to that datatype:
SELECT
CASE
WHEN [T].[SSN] LIKE REPLICATE('[0-9]', 10) THEN [T].[SSN]
ELSE CAST(1000000000 + ROW_NUMBER() OVER(ORDER BY [T].[Name]) AS CHAR(10))
END
FROM [General].[Test] AS [T];
Then you get back your CHAR(10) values - and nothing gets converted to a INT (or BIGINT) and thus looses it's leading zeroes:
(No column name)
1000000001
2591830061
4431776273
1000000004
1000000005
0123456789
0012345678
1000000008