Drop all the synonyms using cursor - sql-server-2008r2-express

I wanted to drop all the synonyms of a database (sql server 2008 r2) using cursor.
environment-database name- 'mydatabase', schema name- 'dbo'..
Can you please guide me as i did try but the statement of while .. end, is not able to drop the synonym.
what logic should be apply w.r.t cursor?

No need to use a cursor. Do it as set:
declare #n char(1)
set #n = char(10)
declare #stmt nvarchar(max)
select #stmt = isnull( #stmt + #n, '' ) +
'drop synonym [' + SCHEMA_NAME(schema_id) + '].[' + name + ']'
from sys.synonyms
exec sp_executesql #stmt

Similar to Jason's answer with some improvements
Use Quotename() function to wrap the names in square brackets
Initialize the #SQL variable to an empty string, this means that the isnull is not required, and means that when you concatenate the results of the query into a single string it doesn't get the type wrong. String literals in a concatenation can take the default nvarchar size and cause your resulting string to be truncated unexpectedly.
Ensure the string literals are also nvarchar by using the N in front of them.
Filter to the dbo schema only, as the OP requested.
Add the sys schema to the sp_executesql call
Totally agree this is not something where you need a cursor.
DECLARE #SQL NVARCHAR(MAX) = N''
SELECT #SQL += N'DROP SYNONYM ' + QUOTENAME(SCHEMA_NAME([schema_id])) + N'.' + QUOTENAME(name) + N';' + Char(13) + Char(10)
FROM sys.synonyms
WHERE SCHEMA_NAME([schema_id]) = N'dbo'
EXEC sys.sp_executesql #SQL

Related

PL-SQL: why does a dynamic statement using bind-variable input not work?

I am trying to create and execute a dynamic SQL statement (using Oracle PL/SQL) and when things didn't work I condensed it to the below two code snippets:
My understanding was that the following two statements would be equivalent (table_name, row_name and row_value are all VARCHAR2 strings):
query_statement VARCHAR2(1000);
-- variant a:
query_statement := 'select * from ' || table_name || ' where ' || row_name || ' = ' || row_value;
dbms_output.put_line('query="' || query_statement || '"');
execute immediate (query_statement);
-- variant b:
query_statement := 'select * from :table where :row = :value';
dbms_output.put_line('query="' || query_statement || '"');
execute immediate (query_statement) using table_name, row_name, row_value;
But not so! The first variant works fine, the second always fails with an error:
** An error was encountered: -903 ORA-00903: invalid table name
From a readability point of view I would prefer variant b but I don't get, why that second variant fails and why the table_name is flagged as wrong. After all that very same name obviously works in variant a. The emitted queries also looks identical to me - of course modulo the fact that the second string still contains placeholders only while the first string contains already concrete values.
Could some kind soul shed some light on this? Why is variant b not working? What am I missing?
As mentioned by #William, usage of bind variable as Tablename is prohibited. On similar lines, you cannot use bind variables as Column Names and Order By clause as well.
Although this is not documented anywhere but its important to note that replacing these ordinal notation affects the execution plan.
You can't use a bind variable as a table_reference. As documented in the link, the table_reference must be static part of the statement.
select * from :table -- ILLEGAL
Contrary to that the usage in the WHERE clause is allowed
where :row = :value -- LEGAL, but questionable
but it doesn't do what you expect. The whereclause returns TRUE, if both bind variables passed are same.
I.e. it is equivalent to
where 'name' = 'xxxx'
and not to
where name = 'xxxx'

Create simple PL/SQL variable - Use Variable in WHERE clause

Thanks for looking...
I've spent hours researching this and I can't believe it's that difficult to do something in PL/SQL that is simple in TSQL.
I have a simple query that joins 2 tables:
Select DISTINCT
to_char(TO_DATE('1899123000', 'yymmddhh24')+ seg.NOM_DATE, 'mm/dd/yyyy') AS "Record Date"
, cd.CODE
, EMP.ID
, EMP.SHORT_NAME
FROM
EWFM.GEN_SEG seg join EWFM.SEG_CODE cd ON seg.SEG_CODE_SK = cd.SEG_CODE_SK
join EMP on seg.EMP_SK = EMP.EMP_SK
where NOM_DATE = vMyDate;
I use Toad Date Point and I'm querying against an Oracle Exadata source. The resulting query will be dropped into a visualization tool like QlikView or Tableau. I'd like to create a simple variable to use the the WHERE clause as you can see in the code.
In this example, NOM_DATE is an integer such as 42793 (2/27/2017) as you can see in the first row "Record Date". Nothing new here, not very exciting... Until... I tried to create a variable to make the query more dynamic.
I've tried a surprising variety of examples found here, all have failed. Such as:
declare
myDate number(8);
Begin
myDate := 42793;
--Fail ORA-06550 INTO Clause is expected
variable nomDate NUMBER
DEFINE nomDate = 42793
EXEC : nomDate := ' & nomDate'
...where NOM_DATE = ( & nomDate) ;
--ORA-00900: invalid SQL statement
and
variable nomDate NUMBER;
EXEC nomDate := 42793;
select count(DET_SEG_SK) from DET_SEG
where NOM_DATE = :nomDate;
--ORA-00900: invalid SQL statement
and several more.. hopefully you get the idea. I've spent a few hours researching stackoverflow for a correct answer but as you can see, I'm asking you. From simple declarations like "Var" to more complex " DECLARE, BEGIN, SELECT INTO...." to actually creating Functions, using cursors to iterate the output.... I still can't make a simple variable to use in a Where clause.
Please explain the error of my ways.
--Forlorn SQL Dev
Since you are using an implicit cursor, you have to select then INTO variables. Now I d not know the data types of you variables, so I have just guessed in this example below, but hopefully you get the point.
Two other things I should mention
Why are you TO_CHARing you DATE. Just use a DATE datatype. Also, I think your format mask is wrong too 1899123000 does not match yymmddhh24.
In explicit cursor expects exactly one row; no rows and you get NO_DATA_FOUND; more than one and you get TOO_MANY_ROWS
Declare
myDate number(8) := 42793;
/* These 4 variable data types are a guess */
v_record_date varchar2(8);
v_cd_code varchar2(10);
v_emp_id number(4);
v_emp_short_name varchar2(100);
BEGIN
Select DISTINCT to_char(TO_DATE('1899123000', 'yymmddhh24')
+ eg.NOM_DATE, 'mm/dd/yyyy') AS "Record Date"
, cd.CODE
, EMP.ID
, EMP.SHORT_NAME
INTO v_record_date, v_cd_code, v_emp_id, v_emp_short_name
FROM EWFM.GEN_SEG seg
join EWFM.SEG_CODE cd
ON seg.SEG_CODE_SK = cd.SEG_CODE_SK
join EMP
on seg.EMP_SK = EMP.EMP_SK
where NOM_DATE = myDate;
END;
/
VARIABLE vMyDate NUMBER;
BEGIN
:vMyDate := 42793;
END;
/
-- or
-- EXEC :vMyDate := 42793;
SELECT DISTINCT
TO_CHAR( DATE '1899-12-30' + seg.NOM_DATE, 'mm/dd/yyyy') AS "Record Date"
, cd.CODE
, EMP.ID
, EMP.SHORT_NAME
FROM EWFM.GEN_SEG seg
join EWFM.SEG_CODE cd
ON seg.SEG_CODE_SK = cd.SEG_CODE_SK
join EMP
on seg.EMP_SK = EMP.EMP_SK
WHERE NOM_DATE = :vMyDate;
You put the variables with getter and setter in a package.
Then use a view that uses the package getter
Personally I prefer to use a collection that way I can do a select * from table (packagage.func(myparam))

How to make first letter of every word as capital letter in SAP HANA

Do we have any method to make first letter of every word as capital letter for a column in SAP HANA?
i.e "ask question" to "Ask Question"
With HANA 2 SPS3, there is a built in function called "Initcap"
SELECT INITCAP('that''s a new function') FROM DUMMY;
That'S A New Function
There is no builtin function for that on SQL level.
You could however write a user-defined function to do just that.
Possibly this site gives you a clue? I'm not familiar with SAP HANA but possibly you can label it as title sentence and do a case normalisation on it?
In T-SQL you could do something like this:
SELECT
UPPER(LEFT(ColumnA,1))+LOWER(RIGHT(ColumnA,(LEN(ColumnA)-1)))
FROM Table1;
You tell the DBMS to make the first letter in upper case, and the rest of the string in lower case. The LEN is needed because I assume the length of the string is not static and in the way of the script it is handled dynamically. The + is CONCAT in other dialects. Regarding whitespaces in ColumnA and the capitalization of the 2nd or more word in you column, I'm trying some stuff that Michael Valentine Jones described on 1-12-2006 here, alsee see part of the code beneath. I get back to this as soon as I figured this out. I'm not sure yet how the union all select statement works. Will take some days (due to the weekend). Anyway, maybe this helps you. Change the REPLACE of ',' with ' ' or something.
-- Create temp table to test inserting values into
create table #t (num int)
-- Create a comma delimited string to test with
declare #str varchar(500)
select #str = '4,2,7,7834,45,24,45,77'
--------------------------------------------------------
---- Code to load the delimited string into a table ----
--------------------------------------------------------
-- Create insert for comma delimited values
declare #sql varchar(8000)
select #sql = 'insert into #t select '+ replace(#str,',',' union all select ')
-- Load values from comma delimited string into a table
exec ( #sql )
I found a piece of T-SQL script that creates a function 'ProperCase' that will do the trick by calling the function in your select statement. See beneath. I foun it here: http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=47718 (by jsmith8858).
create function ProperCase(#Text as varchar(8000))
returns varchar(8000)
as
begin
declare #Reset bit;
declare #Ret varchar(8000);
declare #i int;
declare #c char(1);
select #Reset = 1, #i=1, #Ret = '';
while (#i <= len(#Text))
select #c= substring(#Text,#i,1),
#Ret = #Ret + case when #Reset=1 then UPPER(#c) else LOWER(#c) end,
#Reset = case when #c like '[a-zA-Z]' then 0 else 1 end,
#i = #i +1
return #Ret
end
And for example if you do a SELECT dbo.ProperCase ('ask question WHy iS tHAT'), then you get 'Ask Question Why Is That' as a result.
Hopefully this gets you on your way.

How to swap values between before and after `=` using Oracle?

I have declared a value in parameter #Data as ACCOUNT_NO|none|M=ACCOUNT_NO,ADD1|none|M=ADD1
I need to get a result as ACCOUNT_NO=ACCOUNT_NO|none|M,ADD1=ADD1|none|M.
Which means I need to swap between the values before and after =
I have the SQL Server Query for achieving this but I need Oracle query.
Declare #Data varchar(100)='ACCOUNT_NO|none|M=ACCOUNT_NO,ADD1|none|M=ADD1';
WITH
myCTE1 AS
(
SELECT CAST('<root><r>' + REPLACE(#Data,',','</r><r>') + '</r></root>' AS XML) AS parts1
)
,myCTE2 AS
(
SELECT CAST('<root><r>' + REPLACE(p1.x.value('.','varchar(max)'),'=','</r><r>') + '</r></root>' AS XML) as parts2
FROM myCTE1
CROSS APPLY parts1.nodes('/root/r') AS p1(x)
)
SELECT STUFF
(
(
SELECT ',' + parts2.value('/root[1]/r[2]','varchar(max)') + '=' + parts2.value('/root[1]/r[1]','varchar(max)')
FROM myCTE2
FOR XML PATH(''),TYPE
).value('.','varchar(max)'),1,1,'');
Expected Output if I execute the query ACCOUNT_NO=ACCOUNT_NO|none|M,ADD1=ADD1|none|M. Can anyone give an idea to do this one?
Sounds like a job for REGEXP_REPLACE:
WITH datatab as (select 'ACCOUNT_NO|none|M=ACCOUNT_NO,ADD1|none|M=ADD1' info from dual)
select info,
regexp_replace(info, '([^=]+)=([^=,]+),([^=]+)=([^=,]+)', '\2=\1,\4=\3') new_info
from datatab;
INFO NEW_INFO
--------------------------------------------- ---------------------------------------------
ACCOUNT_NO|none|M=ACCOUNT_NO,ADD1|none|M=ADD1 ACCOUNT_NO=ACCOUNT_NO|none|M,ADD1=ADD1|none|M
(as a complete aside, that's the first time I've ever written a regular expression and had it work first time. Apparently, I have gone over to the dark side... *{;-) )
ETA: If you need this in a procedure/function, you don't need to bother selecting the regular expression, you can do it in PL/SQL directly.
Here's an example of a function that returns the swapped over result:
create or replace function swap_places (p_data in varchar2)
return varchar2
is
begin
return regexp_replace(p_data, '([^=]+)=([^=,]+),([^=]+)=([^=,]+)', '\2=\1,\4=\3');
end swap_places;
/
-- example of calling the function to check the result
select swap_places('ACCOUNT_NO|none|M=ACCOUNT_NO,ADD1|none|M=ADD1') col1 from dual;
COL1
-------------------------------------------------
ACCOUNT_NO=ACCOUNT_NO|none|M,ADD1=ADD1|none|M

SQL Server stored procedure slows every execution

I've got a stored procedure which does many selects and updates with some cursors.
When I execute the procedure the first time, it takes about 30 seconds. Second execution takes about 1 minute. Third about 2 minutes.
Every execution slows the procedure. Now it takes about 10 minutes.
What is going wrong?
Variables:
declare #StatistikStatus nvarchar(100)
declare #SQL as nvarchar(MAX)
declare #Datum as nvarchar(50) --Datum im nvarchar Format
declare #Datumdatetime datetime --Datum im datetime Format
declare #tickethistorieID as uniqueidentifier
declare #id int --ID der Terminauswertung. Wird bei Einträgen benötigt, die pro Ticket mehrere Termine vereinbart haben.
declare #nextTermin datetime --Wird bei Einträgen benötigt, die pro Ticket mehrere Termine vereinbart haben.
declare #status nvarchar(100)
declare #statusdiff as nvarchar(100)
declare #vorStatus as nvarchar(100)
declare #lastid as int
declare #tickethistoriemerker nvarchar(40)
declare #statistikstatusmerker nvarchar(100)
DECLARE #TicketID uniqueidentifier
Sample cursor:
DECLARE C_TicketHistorie CURSOR FOR
SELECT
dbo.TicketHistorie.TicketID,dbo.TicketHistorie.Datum,dbo.tickethistorie.tickethistorieid
FROM
dbo.TicketHistorie INNER JOIN
dbo.Status ON dbo.TicketHistorie.NeueStatusID = dbo.Status.StatusID
INNER JOIN dbo.StatuszuStatistikStatus as s on s.status_ID = dbo.Status.statusid
INNER JOIN dbo.StatistikStatus as ss on s.bewertung_id = ss.id
WHERE
ss.id = 5 AND -- 5 = HNR Terminbestätigung
(dbo.Status.Name = N'Termin vereinbart')
AND ((YEAR(dbo.TicketHistorie.Datum) >= 2011 and day(dbo.TicketHistorie.Datum) >= 27 and month(dbo.TicketHistorie.Datum) >= 12)or YEAR(dbo.TicketHistorie.Datum) >= 2012)
ORDER BY TicketID,Datum asc
OPEN C_TicketHistorie;
FETCH NEXT FROM C_TicketHistorie into #TicketID,#Datumdatetime,#TickethistorieID
WHILE ##FETCH_STATUS = 0
BEGIN
--some inserts etc.
FETCH NEXT FROM C_TicketHistorie into #TicketID,#Datumdatetime,#TickethistorieID
END
CLOSE C_TicketHistorie
DEALLOCATE C_TicketHistorie
I've got 4 cursors.
And some dynamix SQL like this
SET #SQL ='UPDATE Statistik.dbo.terminauswertungab27122011 SET ['
SET #SQL =#SQL + #StatistikStatus+']='''
SET #SQL =#SQL + cast(#TicketHistorieID as NVARCHAR(36))+''''
SET #SQL =#SQL + ' WHERE ID = ' + cast(#ID as nvarchar) +' and ['+#StatistikStatus+'] IS NULL'
EXEC (#SQL)
I call the procedure using SSMS.
at the beginning of the stp i delete the table where the inserts goes into. Then iam doing the Inserts. the table rows are the same every execution
First off, change your cursor declaration to a more efficient cursor:
DECLARE C_TicketHistorie CURSOR
LOCAL STATIC FORWARD_ONLY READ_ONLY
FOR
Next, are you sure that you need a cursor for these operations? It seems that your update, for example, could be accomplished as a single set-based operation instead of a cursor and dynamic SQL, especially if you know the set of column names that could be indicated by #StatistikStatus (where is this determined, by the way?). Here is how you could generate a set-based dynamic SQL update in one swoop instead of a cursor:
DECLARE #sql NVARCHAR(MAX) = N'';
WITH x AS
(
SELECT
-- why only use aliases for the tables you don't reference often?
th.TicketID, th.Datum, th.tickethistorieid
FROM
dbo.TicketHistorie AS th
INNER JOIN dbo.Status AS st
ON th.NeueStatusID = st.StatusID
INNER JOIN dbo.StatuszuStatistikStatus as s
on s.status_ID = st.statusid
INNER JOIN dbo.StatistikStatus as ss
on s.bewertung_id = ss.id
WHERE
ss.id = 5 -- 5 = HNR Terminbestätigung
AND st.Name = N'Termin vereinbart'
-- be smarter about date range queries!
AND dbo.TicketHistorie.Datum >= '2011127'
)
SELECT #sql += N'UPDATE Statistik.dbo.terminauswertungab27122011 SET ['
+ #StatistikStatus+']='''
+ cast(#TicketHistorieID as NVARCHAR(36))+''''
+ ' WHERE ID = ' + cast(#ID as nvarchar) + ' -- nvarchar(WHAT)?
and ['+#StatistikStatus+'] IS NULL;';
Probably a lot more optimization possible here, but as the comments suggest, tough to do without more info.

Resources