Thursday, 13 July 2017

How to Fix SQL72014 and SQL72045 When Importing a BACPAC

Problem

I was importing a BACPAC generated on another server into my local development environment using SQL Server Management Studio and ran into the following errors:

TITLE: Microsoft SQL Server Management Studio
------------------------------

Could not import package.
Warning SQL0: A project which specifies Microsoft Azure SQL Database v12 as the target platform may experience compatibility issues with SQL Server 2014.
Warning SQL72012: The object [databaseXYZ_Data] exists in the target, but it will not be dropped even though you selected the 'Generate drop statements for objects that are in the target database but that are not in the source check box.
Warning SQL72012: The object [databaseXYZ_Log] exists in the target, but it will not be dropped even though you selected the 'Generate drop statements for objects that are in the target database but that are not in the source check box.
Error SQL72014: .Net SqlClient Data Provider: Msg 12824, Level 16, State 1, Line 5 The sp_configure value 'contained database authentication' must be set to 1 in order to alter a contained database. You may need to use RECONFIGURE to set the value_in_use.
Error SQL72045: Script execution error. The executed script:
IF EXISTS (SELECT 1
FROM   [master].[dbo].[sysdatabases]
WHERE  [name] = N'$(DatabaseName)')
BEGIN
ALTER DATABASE [$(DatabaseName)]
SET CONTAINMENT = PARTIAL
WITH ROLLBACK IMMEDIATE;
END

Error SQL72014: .Net SqlClient Data Provider: Msg 5069, Level 16, State 1, Line 5 ALTER DATABASE statement failed.
Error SQL72045: Script execution error. The executed script:
IF EXISTS (SELECT 1
FROM   [master].[dbo].[sysdatabases]
WHERE  [name] = N'$(DatabaseName)')
BEGIN
ALTER DATABASE [$(DatabaseName)]
SET CONTAINMENT = PARTIAL
WITH ROLLBACK IMMEDIATE;
END

(Microsoft.SqlServer.Dac)

Fix

Run the following T-SQL on the target SQL Server instance before importing the BACPAC:

EXEC sp_configure 'contained database authentication', 1;
GO
RECONFIGURE;
GO

Once that setting is enabled, rerun the import.

Why This Happens

The import process is trying to set the target database to partial containment:

ALTER DATABASE [YourDatabaseName]
SET CONTAINMENT = PARTIAL;

If contained database authentication is disabled on the SQL Server instance, that step fails and the import stops with SQL72014 and SQL72045.

This often happens when the BACPAC comes from Azure SQL Database and is being imported into a local SQL Server environment, where contained database authentication may be turned off by default.

Explanation

At first I suspected the issue might be caused by a corrupt BACPAC or Transparent Data Encryption (TDE), but the real cause was much simpler: the import required support for a contained database.

A partially contained database reduces dependencies on the master database and allows authentication and configuration to live more at the database level rather than relying entirely on server-level logins.

Because this has security implications, SQL Server does not always enable it by default on local or on-premises instances.

Notes

  • SQL72014 and SQL72045 are the main errors causing the import failure.
  • The SQL72012 warnings about data and log objects are not the root cause here.
  • For most local development environments, enabling contained database authentication is enough to complete the import successfully.

Further Reading

July 13, 2017

Sunday, 12 October 2014

How to Get Combinations of Rows from Multiple SQL Tables

Getting combinations of rows from database tables is simple. First you have to understand the difference between Cartesian product and Permutation before we go any further.

I have manually printed out all the combinations in example containing three tables with respective values for the understanding.

Example
Table1     Table2     Table3
a1             b1           c1
a2             b2           c2
a3                            c3
                                c4
The results should be as follow

a1,b1,c1
a1,b1,c2
a1,b1,c3
a1,b1,c4

a1,b2,c1
a1,b2,c2
a1,b2,c3
a1,b2,c4

a2,b1,c1
a2,b1,c2
a2,b1,c3
a2,b1,c4

a2,b2,c1
a2,b2,c2
a2,b2,c3
a2,b2,c4

a3,b1,c1
a3,b1,c2
a3,b1,c3
a3,b1,c4

a3,b2,c1
a3,b2,c2
a3,b2,c3
a3,b2,c4
The above results are not permutation, because you need the combinations to always follow the unique format. So, in conclusion the Cartesian product concept is the right way to go.

Solution
We will use Cartesian Join or Cross Join for the solution of above example. Cross Join returns the Cartesian product of rows from tables in the join. Each row in the first table is matched with every row in the second table and so on.
select *
from
  table1
  cross join table2
  cross join table3
Same thing as implicit cross join:
select *
from
  table1, table2, table3



/Adnan

October 12, 2014

Thursday, 11 September 2014

Get Usage report of Content Types in Optimizely CMS

Large Optimizely or EPiServer projects tend to collect old page types over time. New templates are introduced, editors move on to newer content types, and some older page types quietly stop being used.

If you are cleaning up a long-running CMS solution, one of the first things worth checking is which page types are still in use and which ones have a page count of zero.

The SQL query below gives you a quick usage report for page types. It does not cover block types, but it is a useful first step when auditing legacy CMS projects.

Quick SQL Audit

Run the following query in SQL Server to list page type names, filenames, and the number of pages using each type:

SELECT
    pt.Name,
    pt.Filename,
    COUNT(p.pkID) AS PageCount
FROM tblPageType AS pt
LEFT JOIN tblPage AS p
    ON p.fkPageTypeID = pt.pkID
GROUP BY
    pt.Name,
    pt.Filename
ORDER BY
    PageCount DESC,
    pt.Name;

Why This Is Useful

This report helps you quickly spot:

  • page types that are heavily used
  • page types that are rarely used
  • page types with a PageCount of 0, which may be candidates for cleanup

Before You Run It

Empty the recycle bin first. Deleted content can still affect the result and make unused page types look active when they are not.

Important Note

A page count of zero is a strong signal, but it should not automatically mean “safe to delete”. Before removing a page type from code, double-check whether it is still referenced by old templates, import jobs, migrations, or content type availability rules.

For older self-hosted EPiServer or Optimizely CMS solutions, this is a quick and practical way to start a cleanup exercise without building a custom report first.

September 11, 2014

Tuesday, 9 September 2014

How to Change a DNN Username Using SQL Server

Sometime users request to change their usernames, the reason could be they don't want to lose their activities in the system. There can be many other reasons but the fact is I have deal with these request time to time.So here is a solutions.

If you are going to change the username from SQL Server, make it repeatable, you might want to wrap the syntax in a transaction. You don't want want the two tables to be out of sync. 

Here is sample series of T-Sql statements. Should be easy to convert to a stored procedure

declare @oldName nvarchar(128)
declare @newName nvarchar(128)
declare @error_var int, @rowcount_var int
declare @newNameCount int

select @oldName = 'someUsername'
select @newName = 'newUsername'


begin transaction

select @newNameCount = count(*)
  from Users
  where Username = @newName
if @newNameCount > 0
begin
  RAISERROR('Username already exists. @newName=%s', 10, 1, @newName)
  ROLLBACK TRANSACTION
  RETURN
end

update Users
set Username = @newName
where Username = @oldName

SELECT @error_var = @@ERROR, @rowcount_var = @@ROWCOUNT
IF @rowcount_var <> 1 OR @error_var <> 0
BEGIN
  RAISERROR('Could not Update User.Username. @oldName=%s', 10, 1, @oldName)
  ROLLBACK TRANSACTION
  RETURN
END


update aspnet_Users
set
  Username = @newName,
  LoweredUserName = LOWER(@newName)
where LoweredUserName = LOWER(@oldName)

SELECT @error_var = @@ERROR, @rowcount_var = @@ROWCOUNT
IF @rowcount_var <> 1 OR @error_var <> 0
BEGIN
  RAISERROR('Could not Update aspnet_Users.Username. @oldName=%s', 10, 1, @oldName)
  ROLLBACK TRANSACTION
  RETURN
END

Commit transaction
go 
September 09, 2014

How to Find Duplicate Records in SQL Server

Here's a handy query for finding duplicates in a table. Suppose you want to find all email addresses in a table name users that exist more than once:
SELECT email, 
COUNT(email) AS NumOccurrences
FROM users
GROUP BY email
HAVING ( COUNT(email) > 1 )


You could also use this technique to find rows that occur exactly once:

SELECT email
FROM users
GROUP BY email
HAVING ( COUNT(email) = 1 )
September 09, 2014

SQL Server Security Updates for Supported Versions

Microsoft released a security bulletin covering several issues that could potentially affect SQL Server; these exploits include remote code execution, denial of service, information disclosure and elevation of privilege. You should test these patches on all machines running SQL Server, including those running only client tools (e.g. Management Studio or Management Studio Express). The updates affect the following versions of SQL Server:
  • SQL Server 2005 SP3
  • SQL Server 2005 SP4
  • SQL Server 2008 SP1
  • SQL Server 2008 SP2
  • SQL Server 2008 R2
So, depending on your SQL Server version (run SELECT @@VERSION;), here is what you should do:

If you are running... And your build number is... Your best course of action is probably to...
SQL Server 2005 Less than 9.0.4035
 
Upgrade to Service Pack 3 (9.0.4035) or Service Pack 4 (9.0.5000), then come back for the GDR
Exactly 9.0.4035 (SP3) Install the SP3 GDR (9.0.4060) from KB #2494113
 
Between 9.0.4036 and 9.0.4339 (a) Upgrade to Service Pack 4 (9.0.5000), then come back for the GDR
OR
(b) Install the SP3 QFE (9.0.4340) from KB #2494112
 
Exactly 9.0.5000 (SP4) Install the SP4 GDR (9.0.5057) from KB #2494120
 
Greater than 9.0.5000
 
Install the SP4 QFE (9.0.5292) from KB #2494123
 
SQL Server 2008 Less than 10.0.2531
 
Upgrade to Service Pack 1 (10.0.2531) or Service Pack 2 (10.0.4000), then come back for the GDR
Exactly 10.0.2531 (SP1) Install the SP1 GDR (10.0.2573) from KB #2494096
 
Between 10.0.2532 and 10.0.2840 (a) Upgrade to Service Pack 2 (10.0.4000), then come back for the GDR
OR
(b) Install the SP1 QFE (10.0.2841) from KB #2494100
 
Exactly 10.0.4000 (SP2) Install the SP2 GDR (10.0.4064) from KB #2494089
 
Greater than 10.0.4000 Install the SP2 QFE (10.0.4311) from KB #2494094
 
SQL Server 2008 R2 Exactly 10.50.1600 (RTM) Install the GDR (10.50.1617) from KB #2494088
 
Between 10.50.1601 and 10.50.1789 Install the QFE (10.50.1790) from KB #2494086
 
Greater than 10.50.1790
(e.g. 10.50.2418 or 10.50.2425)
 
Wait for the final release of Service Pack 1
Watch for cumulative update or updates to MS11-049
At this time there is no fix for the CTP of SQL Server 2008 R2 SP1


What is the difference between a GDR and a QFE? 

A GDR (general distribution release) is one that Microsoft support deems is necessary for all systems running SQL Server. A QFE (quick fix engineering) is one that does not affect everyone. Why are there two releases for this important fix? Well, one reason is that after a QFE is installed, it is no longer possible to install a GDR. So, if you have a system that has had previous cumulative updates or QFEs applied, the GDR might not work for you. If you have a system that is exactly at one of the levels described above, then the GDR is probably the better choice, because it will allow you to install either a GDR or a QFE in the future, whereas installing a QFE on such a system kind of paints you into a corner.
There is also a GDR available if you are running Management Studio Express 2005 (but none seem to be listed at this time for the 2008 or 2008 R2 versions):

KB #2546869
September 09, 2014

How to Clean SQL Server Tables and Reset Identity Columns

I had a problem while back to clean up my database and reset identity columns in all tables. But as we all know the chaos of the database, trace relations and delete records from child tables before parent tables because of foreign key constrains. By manually doing it could take so much time even the database is not that huge. Through some research on Google and books I was able to come up with a solution to achieve my target in few steps. The solution was to use built in stored procedure sp_MSforeachtable (which I already discussed in my previous blog post). So here is the following code bellow  for how I re-zeroed my Database:

/*Disable Constraints & Triggers*/
exec sp_MSforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'
exec sp_MSforeachtable 'ALTER TABLE ? DISABLE TRIGGER ALL'

 /*Perform delete operation on all table for cleanup*/
exec sp_MSforeachtable 'DELETE ?'

/*Enable Constraints & Triggers again*/
exec sp_MSforeachtable 'ALTER TABLE ? CHECK CONSTRAINT ALL'
exec sp_MSforeachtable 'ALTER TABLE ? ENABLE TRIGGER ALL'

/*Reset Identity on tables with identity column*/
exec sp_MSforeachtable 'IF OBJECTPROPERTY(OBJECT_ID(''?''), ''TableHasIdentity'') = 1 BEGIN DBCC CHECKIDENT (''?'',RESEED,0) END' 
September 09, 2014

How to List SQL Server Tables and Their Row Counts

I was trying to identify which tables were affected by an update though an application (3rd party). There were more than 300+ tables in the Database. I was hoping to avoid checking each of them for changes. To get the list of tables and their rows counts in a database you can use the following SQL query before and after the update.
SELECT
[TableName] = so.name,
[RowCount] = MAX(si.rows)
FROM
sysobjects so,
sysindexes si
WHERE
so.xtype = 'U'
AND
si.id = OBJECT_ID(so.name)
GROUP BY
so.name
ORDER BY
2 DESC

Note:
The sysindexes table is usually a little bit inaccurate, because it is not updated constantly. It will also include the 'dtproperties' table, which is one of those hybrid tables that falls neither under the 'system' nor 'user' category. It does not appear in Enterprise Manager's "Tables" view if you choose to hide system objects, but it shows up above.

In any case, it is generally not recommended to query against the system objects directly, so please only use the above for rough, ad-hoc guesstimates.
September 09, 2014

How to Delete or Truncate All Tables in SQL Server

To delete/drop/truncate all the tables from Database, you can use the following SQL commads to perform the desired function
EXEC sp_MSforeachtable @command1 = "DELETE FROM ?"
EXEC sp_MSforeachtable @command1 = "TRUNCATE TABLE ?"

Explanation

sp_MSforeachtable is a hidden Stored Procedure in sql server, that will execute for all the tables for database (no rollback)
@command1 is variable which will run against each table for connected database.
Whatever you will write in the double quotes, that will be act as a command for each table, where '?' is the name of the table.

Word of caution. Make sure execute these commands on test Database before actually executing in the desired database
September 09, 2014