Find recent object changes in SQL Server Database - sql-server-2008

I've added and modified several (new and existing resp.) tables and stored procs, for a particular database and server, in last 3 months.
I was thinking if there's any SQL query by which I can determine all those changes.
Thanks.

Query the sys.objects table to find the objects that changed and filter by modify_date and type; U = User table, P = Stored procedure.
select *
from sys.objects
where (type = 'U' or type = 'P')
and modify_date > dateadd(m, -3, getdate())
This approach will tell you what objects have changed, but not the specific changes.

Hi you can get the changed/modified db object details with this query
select name,create_date,modify_date
from sys.procedures
order by modify_date desc
Thanks

I don't think you're going to be able to find what you're looking for. SQL Server just doesn't track that information out of the box.
To handle this in the future, you can use some kind of source control (redgate, for one: http://www.red-gate.com/products/sql-development/sql-source-control),
or you can set up a DDL trigger (one such technique is described here: https://dba.stackexchange.com/questions/33541/how-to-keep-history-of-sql-server-stored-procedure-revisions/33544#33544).

Related

Get schema of stored procedure which returned error

I have several procedures with same name but in different schemas. When these procedures raise an error, it is possible in parent procedure (which is calling these nested stored procedures) get schema of the procedure which raised an error ? For example i can get name from ERROR_PROCEDURE() but is there some option to get also SCHEMA ? Because otherwise i am not sure which exactly procedure throwed an error if there are many with same name.
I guess this feature is still missing
https://connect.microsoft.com/SQLServer/feedback/details/124627/schema-not-reported-in-the-error-procedure-function
but is there some workaround for this ?
Sadly, there is no 100% Workaround for this limitation in SQL-Server.
Shame on the MSSQL Dev Team for not rectifying this, well over a Decade later.
It should be as simple as adding a New Function like ERROR_ProcedureSchema() or ERROR_PROCID().
Here is a revived Post Requesting this Feature from way back in May of 2005:
https://feedback.azure.com/forums/908035-sql-server/suggestions/32894584-schema-not-reported-in-the-error-procedure-functio
I prefer to Log as much detail as possible about Exceptions I capture in my custom Error Handling Logic.
This is the best I could come up with to find the Schema Name:
DECLARE #Error_ProcSchemaName nVarChar(128)--Leave as Null if found in more than 1 Schema.
--Only Populate the #Error_ProcSchemaName if it Belongs to 1 Schema. - 04/08/2019 - MCR.
SELECT #Error_ProcSchemaName = S.name
FROM sys.objects as O
JOIN sys.schemas as S
ON S.schema_id = O.schema_id
JOIN
(
SELECT O.name[ObjectName], COUNT(*)[Occurrences]
FROM sys.objects as O
GROUP BY O.name
) AS Total
ON Total.ObjectName = O.name
WHERE O.name = ERROR_PROCEDURE()
AND Total.Occurrences = 1
Avoid using anything like OBJECT_SCHEMA_NAME(OBJECT_ID(ERROR_PROCEDURE())) as the string you pass into OBJECT_ID() should already have the Schema in it (which ERROR_PROCEDURE() does not).
Otherwise it will default to your Default Schema, which (in most cases) is dbo.
Run this Query to View all your Object Names that are Reused across Schemas:
--View Object Names that Exist in Multiple Schemas: - 04/08/2019 - MCR.
SELECT S.name[SchemaName], O.name[ObjectName], Total.Occurrences,
O.type[Type], O.type_desc[TypeDesc],
O.object_id[ObjectID], O.principal_id[PrincipalID], O.parent_object_id[ParentID],
O.is_ms_shipped[MS], O.create_date[Created], O.modify_date[Modified]
FROM sys.objects as O
JOIN sys.schemas as S
ON S.schema_id = O.schema_id
JOIN
(
SELECT O.name[ObjectName], COUNT(*)[Occurrences]
FROM sys.objects as O
GROUP BY O.name
) AS Total
ON Total.ObjectName = O.name
WHERE Total.Occurrences > 1
ORDER BY [ObjectName], [SchemaName]
If you only have a few Objects (Sprocs and Triggers) that overlap, then you might be okay not knowing the Schema as it may be obvious where it originated from.
However, if this is not the case, then you may need to either:
Change the Name of the Sproc/Trigger to make it Unique.
This option goes against the very fiber of my being.
If you are using Advanced Error Handling, then manually add the Schema of your Sproc/Trigger with OBJECT_SCHEMA_NAME(##PROCID)
in your Catch-Block when logging the Error.
Note: These options may not be possible due to the use of 3rd Party Sprocs you are not allowed to edit.
When Troubleshooting with multiple Sprocs/Triggers that share the same Name, you might be able to write a Custom Wrapper-Sproc to call your 3rd Party Sproc, then Log any exception thrown in your Wrapper to know exactly which Schema/Sproc caused it.
The Code Smell:
If you have multiple Sprocs/Triggers with the same name spread across various Schemas
then I would call that a "Code Smell".
Meaning, your Architecture is flawed.
You may not be properly encapsulating your logic for reuse.
There will be times when a name overlaps Schemas, but this should be rare and by coincidence only.
Misappropriating Schemas for Handling Multi-Tenant / UserGroup Access:
If you are trying something Multi-Tenant (storing data from different Organizations/UserGroups in the same Database and preventing them from seeing eachother's info) and running almost the same logic in each Schema that shares the Object Name, then that's a Design Problem.
You should have your data in Different Databases if Users will be accessing it directly
or have a TenantID or UserGroupID you always pass in and filter on everywhere when Users will be accessing from a Custom Application.
Some possible solutions I can think of:
Renaming each Stored Procedure so that they have different names in the different schemas.
Adding some debugging output to the Stored Procedures so that when they are being executed, you can see which one was in progress when your error occurred.
Running the SQL Profiler to see what is being called at the time your error occurs.
However, these are coming more from the perspective of trying to troubleshoot an issue you're having right now, rather than building in some error handling for potential future troubleshooting. You could always get these Stored Procedures to write some log files to disk somewhere so you can interrogate those logs when an error is experienced perhaps.

Prompt user to input a variable in MySQL

At school, I believe I work with Oracle SQL Developer when writing SQL. And in this I can type:
SELECT Book_Title, Auth_ID
FROM book
WHERE Auth_ID = '&Enter ID';
This will then display a little message box where the user can enter an ID number to see all the books written by an author with that ID number.
I want to know if there is a way to do this in MySQL. I have looked and the nearest thing I can find is setting a variable before hand, which is not quite what I'm looking for:
SET #EnterID := 2;
select Book_Title, Auth_ID
from book
where Auth_ID = #EnterID;
The above statement in MySQL will return all the books with author ID of 2, but only because I set it to that previously. I want the user to be able to enter the variable.
Thanks.
Oracle has the concept of interactive queries, those that as you said you can run by adding the '&' before your variables names, that is a variable substitution, this concept doesn't exist in MySql, MySql is not interactive and requires the user to enter the values in the variables by using the keyword 'SET' and # (instead of & like in Oracle).
So, no, you cannot do what you are looking for since this is not a client-side implementation either.
BTW, I just noticed this was asked so many years ago, amazing that this is still not added as a feature in mysql.
For a prompt, you must put the char ':' followed by the name of the variable
Example :
select *
from YOUR_TABLE
where YOUR_COLUMN = :your_var
mysql is to run SQL queries .SQL is a query language, it is not for user interaction
See : How to ask MySQL to prompt for values in a query?

when using union that uses values from a form it creates a error?

I have this union statement when I try to take parameters from a form and pass it to a union select statement it says too many parameters. This is using MS ACCESS.
SELECT Statement FROM table 1 where Date = Between [Forms]![DateIN]![StartDate]
UNION
SELECT Statement FROM table 2 where Date = Between [Forms]![DateIN]![StartDate]
This is the first time I am using windows DB applications to do Database apps. I am Linux type of person and always use MySQL for my projects but for this one have to use MS Access.
Is there anther way to pass parameters to UNION Statement because this method of defining values in a form can work on Single SELECT statements. But I don't know why this problem exist.
Between "Determines whether the value of an expression falls within a specified range of values" like this ...
expr [Not] Between value1 And value2
But your query only gives it one value ... Between [Forms]![DateIN]![StartDate]
So you need to add And plus another date value ...
Between [Forms]![DateIN]![StartDate] And some_other_date
Also Date is a reserved word. If you're using it as a field name, enclose it in brackets to avoid confusing the db engine: [Date]
If practical, rename the field to avoid similar problems in the future.
And as Gord pointed out, you must also bracket table names which include a space. The same applies to field names.
Still getting problems when using this method of calling the values or dates from the form to be used on the UNION statement. Here is the actual query that I am trying to use.
I don't want to recreate the wheel but I was thinking that if the Date() can be used with between Date() and Date()-6 to represent a 7 days range then I might have to right a module that takes the values from the for and then returns the values that way I can do something like Sdate() and Edate() then this can be used with Between Sdate() and Edate().
I have not tried this yet but this can be my last option I don't even know if it will work but it is worth a try. But before i do that i want to try all the resources that Access can help me make my life easy such as its OO Stuff it has for helping DB programmers.
SELECT
"Expenditure" as [TransactionType], *
FROM
Expenditures
WHERE
(((Expenditures.DateofExpe) Between [Forms]!Form1![Text0] and [Forms]![Form1]![Text11]))
UNION
SELECT
"Income" as [TransactionType], *
FROM
Income
WHERE
(((Income.DateofIncom) Between [Forms]!Form1![Text0] and [Forms]![Form1]![Text11] ));
Access VBA has great power but I don't want to use it as of yet as it will be hard to modify changes for a user that does not know how to program. trying to keep this DB app simple as possible for a dumb user to fully operate.
Any comments is much appreciated.

How to find out the changes happened for all objects

How I can find out the changes happened in database like modifying functions, table indexes, procedures and adding or removing columns.
Here in this query
select * from sys.objects
where type IS NOT NULL
and modify_date between '2013-07-21' and '2013-07-29'
but here I am getting created objects list and modifying list, but if I deleted any object it is not showing anything.
How can I get the all the changes happened in database between specific dates?
Try a source control solution for SQL. I've used RedGate's SQL Source Control before, and it records a history of changes like this, including who made the change, and what was changed.
http://www.red-gate.com/products/sql-development/sql-source-control/
It's a bit expensive, but it's good. I don't know if there's a way to do it (especially deletions) just with SQL itself.
Many of these incidents are recorded in the default trace.
DECLARE #path NVARCHAR(260);
SELECT
#path = REVERSE(SUBSTRING(REVERSE([path]),
CHARINDEX(CHAR(92), REVERSE([path])), 260)) + N'log.trc'
FROM sys.traces
WHERE is_default = 1;
SELECT
LoginName,
HostName,
StartTime,
ObjectName,
TextData -- may or may not be populated
FROM sys.fn_trace_gettable(#path, DEFAULT)
WHERE EventClass IN
(
164, -- object:altered
46, -- object:created
47 -- object:deleted
)
AND StartTime >= '20130721' AND StartTime < '20130730';
Why you should never use BETWEEN for date range queries.

MySQL "in" command

I want to know how we can do this using the IN comparison syntax.
The current SQL query is :
select * from employee
where (employeeName = 'AJAY' and month(empMonth) = month(curdate()))
or (employeeName ='VINAY' and month(empMonth) = month(curdate()))
I tried it using IN comparison function, but am unable to properly set the pieces. Can any one help me?
select * from employee
where employeeName in ('AJAY','VINAY')
and month(empMonth) = month(curdate()); // ERROR.
I tried it in MySQL Query.
Thank You,
Sindhu
Your solution is fine for most DBMS (data-base management systems). As far as I know it is no problem in MySQL. But some years ago I had similar problems in DB2 and also in another more exotic DBMS named "Focus".
Maybe this can help:
Put the complete where-block into a pair of brackets.
Inside this block put each comparison in a pair of brackets again.
Move the IN-Comparison to the end of the where-block.
This would transform your example into this code:
SELECT *
FROM employee
WHERE (
(month(empMonth) = month(curdate())
AND
(employeeName IN ('AJAY','VINAY'))
);