<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Discrete Information &#187; MS SQL</title>
	<atom:link href="http://www.discreteinformation.com/tag/ms-sql/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.discreteinformation.com</link>
	<description>Providing a finite amount of information.</description>
	<lastBuildDate>Sun, 23 Aug 2009 03:42:50 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Using OUTPUT with UPDATE</title>
		<link>http://www.discreteinformation.com/2009/06/using-output-with-update/</link>
		<comments>http://www.discreteinformation.com/2009/06/using-output-with-update/#comments</comments>
		<pubDate>Mon, 08 Jun 2009 03:52:49 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[MS SQL]]></category>
		<category><![CDATA[OUTPUT]]></category>

		<guid isPermaLink="false">http://www.discreteinformation.com/?p=62</guid>
		<description><![CDATA[As seen in earlier posts, a very useful clause in SQL Server 2005 and beyond is OUTPUT. Here is an example within an UPDATE statement.
Here&#8217;s our table structure:
IF EXISTS (SELECT * FROM sys.tables WHERE name = 'users')
BEGIN
  DROP TABLE [users];
END;

CREATE TABLE [users] (
  [user_id] INT PRIMARY KEY IDENTITY(1,1),
  username VARCHAR(16),
  [password] [...]]]></description>
			<content:encoded><![CDATA[<p>As seen in earlier posts, a very useful clause in SQL Server 2005 and beyond is <code>OUTPUT</code>. Here is an example within an <code>UPDATE</code> statement.</p>
<p>Here&#8217;s our table structure:</p>
<pre>IF EXISTS (SELECT * FROM sys.tables WHERE name = 'users')
BEGIN
  DROP TABLE [users];
END;

CREATE TABLE [users] (
  [user_id] INT PRIMARY KEY IDENTITY(1,1),
  username VARCHAR(16),
  [password] VARCHAR(16),
  email VARCHAR(128)
);</pre>
<p>Here is a <code>changeUserName</code> procedure to update a user&#8217;s username, using an <code>OUTPUT</code> clause:</p>
<pre>
CREATE PROC changeUserName
  @user_ip varchar(15),
  @password varchar(16),
  @username_old varchar(16),
  @username_new varchar(16)
AS

  SET NOCOUNT ON;

  CREATE TABLE #updatedUser(
    user_id INT,
    username_old VARCHAR(16),
    username_new VARCHAR(16));

  UPDATE [users]
    SET [username] = @username_new
  OUTPUT DELETED.user_id, DELETED.username, INSERTED.username
    INTO #updatedUser(user_id, username_old, username_new)
  WHERE [users].username = @username_old
    AND CAST([users].[password] AS VARBINARY(16))
      = CAST(@password AS VARBINARY(16));

  SET NOCOUNT OFF;

  SELECT user_id, username_old, username_new
    FROM #updatedUser;

  DROP TABLE #updatedUser;
</pre>
<p>Here is an example of that procedure in action:</p>
<pre>
EXEC [addUser] @user_ip = '192.168.1.2',
  @username = 'john',
  @password = 'john!password',
  @email = 'john@yahoo.com';

user_id
-----------
1

EXEC [changeUserName]
  @user_ip = '192.168.1.1',
  @username_old = 'john',
  @username_new = 'john_new',
  @password='john!password';

user_id     old_username     new_username
------- ---------------- ----------------
1           john         john_new
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.discreteinformation.com/2009/06/using-output-with-update/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Don&#8217;t Forget the OUTPUT Clause</title>
		<link>http://www.discreteinformation.com/2009/05/dont-forget-the-output-clause/</link>
		<comments>http://www.discreteinformation.com/2009/05/dont-forget-the-output-clause/#comments</comments>
		<pubDate>Wed, 27 May 2009 01:22:21 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[MS SQL]]></category>
		<category><![CDATA[OUTPUT]]></category>

		<guid isPermaLink="false">http://www.discreteinformation.com/?p=44</guid>
		<description><![CDATA[One of the more useful clauses available in SQL Server 2005 and beyond is OUTPUT, but it is rarely seen in use. Here is a quick example of how to use it within an INSERT statement.
Let&#8217;s setup our table structure first:
IF EXISTS (SELECT * FROM sys.tables WHERE name = 'users')
BEGIN
  DROP TABLE [users];
END;

CREATE TABLE [users] [...]]]></description>
			<content:encoded><![CDATA[<p>One of the more useful clauses available in SQL Server 2005 and beyond is <code>OUTPUT</code>, but it is rarely seen in use. Here is a quick example of how to use it within an <code>INSERT</code> statement.</p>
<p>Let&#8217;s setup our table structure first:</p>
<pre>IF EXISTS (SELECT * FROM sys.tables WHERE name = 'users')
BEGIN
  DROP TABLE [users];
END;

CREATE TABLE [users] (
  [user_id] INT PRIMARY KEY IDENTITY(1,1),
  username VARCHAR(16),
  [password] VARCHAR(16),
  email VARCHAR(128)
);

IF EXISTS (SELECT * FROM sys.tables WHERE name = 'login_activity')
BEGIN
  DROP TABLE [login_activity];
END;

CREATE TABLE [login_activity] (
  user_id INT,
  user_ip VARCHAR(15),
  login_username VARCHAR(16),
  login_success BIT,
  login_time DATETIME
);</pre>
<p>Let&#8217;s assume we want an <code>addUser</code> procedure to create a user, log in said user, and return the new user&#8217;s <code>user_id</code>. Here is how we could do that with the <code>OUTPUT</code> clause:</p>
<pre>
CREATE PROC addUser
  @user_ip VARCHAR(15),
  @username VARCHAR(16),
  @password VARCHAR(16),
  @email VARCHAR(128)
AS

SET NOCOUNT ON;

CREATE TABLE #new_user(user_id INT);

INSERT INTO users (username, [password], email)
OUTPUT inserted.[user_id] INTO #new_user(user_id)
VALUES (@username, @password, @email);

INSERT INTO login_activity(user_id, login_ip, login_username,
  login_success, login_time)
SELECT user_id, @username, @user_ip, 1, CURRENT_TIMESTAMP
FROM #new_user;

SET NOCOUNT OFF;

SELECT user_id
FROM new_user;
</pre>
<pre>
EXEC [addUser] @user_ip = '192.168.1.1',
  @username = 'bob',
  @password = 'bob!password',
  @email = 'bob@gmail.com';

user_id
-----------
1

EXEC [addUser] @user_ip = '192.168.1.2',
  @username = 'john',
  @password = 'john!password',
  @email = 'john@yahoo.com';

user_id
-----------
2
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.discreteinformation.com/2009/05/dont-forget-the-output-clause/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Paging Stored Procedure in MS SQL, By Page</title>
		<link>http://www.discreteinformation.com/2009/05/ms-sql-server-paging-method-1/</link>
		<comments>http://www.discreteinformation.com/2009/05/ms-sql-server-paging-method-1/#comments</comments>
		<pubDate>Sun, 24 May 2009 19:31:39 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[MS SQL]]></category>
		<category><![CDATA[Pagination]]></category>

		<guid isPermaLink="false">http://www.discreteinformation.com/?p=15</guid>
		<description><![CDATA[MS SQL has the TOP clause, and it works very similar to MySQL&#8217;s LIMIT clause. However, the TOP clause in MS SQL provides no sort of OFFSET equivalent. Thus the TOP clause is virtually useless for a proper paging control. Let&#8217;s see one way we can work around that limitation:
For reference, here are the CREATE [...]]]></description>
			<content:encoded><![CDATA[<p>MS SQL has the <code>TOP</code> clause, and it works very similar to MySQL&#8217;s <code>LIMIT</code> clause. However, the <code>TOP</code> clause in MS SQL provides no sort of <code>OFFSET</code> equivalent. Thus the <code>TOP</code> clause is virtually useless for a proper paging control. Let&#8217;s see one way we can work around that limitation:</p>
<p>For reference, here are the <code>CREATE</code> and <code>INSERT</code> statements for the <code>[users]</code> table used in this example.</p>
<pre>
CREATE TABLE [users] (
  user_id INT PRIMARY KEY,
  username VARCHAR(16),
  password VARCHAR(16),
  email VARCHAR(128)
);

INSERT INTO [users] (user_id, username, password, email)
SELECT 1, 'bob', 'bob!password', 'bob@gmail.com'
UNION ALL
SELECT 2, 'john', 'john!password', 'john@yahoo.com'
UNION ALL
SELECT 3, 'kim', 'kim!password', 'kim@msn.com'
UNION ALL
SELECT 4, 'rachel', 'rachel!password', 'rachel@aol.com'
UNION ALL
SELECT 5, 'frank', 'frank!password', 'frank@email.com';
</pre>
<p>Now, let&#8217;s create a stored procedure to search our <code>[users]</code> table. It takes three paramaters. The <code>@email</code> paramater is a full or partial e-mail to search. <code>@page</code> is the page to be displayed, and <code>@per_page</code> is the number of results per page.</p>
<pre>
CREATE PROC searchUsersByEmail
  @email VARCHAR(128),
  @page SMALLINT,
  @per_page SMALLINT
AS

SET @last_page = (@nbr_results - 1) / @per_page + 1;

SELECT
  @nbr_results = COUNT(*)
FROM [users] AS u
WHERE u.email LIKE '%' + @email + '%';

SET @last_page = @nbr_results / @per_page; 

IF (@page = 1)
BEGIN
  -- Special first page case:
  SELECT TOP (@per_page)
    u.user_id,
    u.username,
    u.email
  FROM [users] AS u
  WHERE u.email LIKE '%' + @email + '%'
  ORDER BY u.email ASC;
END;
ELSE IF (@page = @last_page)
BEGIN
  -- Special last page case:
  SELECT s0.*
  FROM (
    SELECT TOP (@nbr_results - (@last_page - 1) * @per_page)
      u.user_id,
      u.username,
      u.email
    FROM [users] AS u
    WHERE u.email LIKE '%' + @email + '%'
    ORDER BY u.email DESC
  ) AS s0
  ORDER BY s0.email ASC;
END;
ELSE IF (@page > @last_page)
BEGIN
  -- Error / Empty set case, replace with error if desired.
  SELECT
    u.user_id,
    u.username,
    u.email
  FROM [users] AS u
  WHERE 1 = 0;
END;
ELSE
BEGIN
  -- All other cases:
  SELECT s1.*
  FROM (
    SELECT TOP (@per_page) s0.*
    FROM (
      SELECT TOP (@page * @per_page)
        u.user_id,
        u.username,
        u.email
      FROM [users] AS u
      WHERE u.email LIKE '%' + @email + '%'
      ORDER BY u.email ASC
    ) AS s0
    ORDER BY s0.email DESC
  ) AS s1
  ORDER BY s1.email ASC;
END;
</pre>
<p>Now let&#8217;s test our search procedure by searching for all e-mails with &#8220;.com&#8221;:</p>
<pre>
[searchUsersByEmail] @email = '.com', @page = 1, @per_page = 3;

user_id     username email
----------- -------- ----------------
1           bob      bob@gmail.com
5           frank    frank@email.com
2           john     john@yahoo.com

[searchUsersByEmail] @email = '.com', @page = 2, @per_page = 3;

user_id     username email
----------- -------- ----------------
3           kim      kim@msn.com
4           rachel   rachel@aol.com
</pre>
<p>That&#8217;s it. Now you have a functional procedure in MS SQL as an alternative to MySQL&#8217;s <code>LIMIT x OFFSET y</code> clause.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.discreteinformation.com/2009/05/ms-sql-server-paging-method-1/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Link MySQL to 64-bit MS SQL Server</title>
		<link>http://www.discreteinformation.com/2009/05/link-mysql-to-64-bit-ms-sql-server/</link>
		<comments>http://www.discreteinformation.com/2009/05/link-mysql-to-64-bit-ms-sql-server/#comments</comments>
		<pubDate>Thu, 21 May 2009 03:28:42 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[SQL]]></category>
		<category><![CDATA[64-bit]]></category>
		<category><![CDATA[MS SQL]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[ODBC]]></category>

		<guid isPermaLink="false">http://www.discreteinformation.com/?p=9</guid>
		<description><![CDATA[The key to adding a MySQL instance as a linked server within 64-bit MS SQL Server is finding an appropriate x64 ODBC provider. Microsoft had previously depreciated and eliminated this feature for the 64-bit version of SQL Server.
They recently reversed their decision, and claim no new plans to depreciate this provider. However, the link is [...]]]></description>
			<content:encoded><![CDATA[<p>The key to adding a MySQL instance as a linked server within 64-bit MS SQL Server is finding an appropriate x64 ODBC provider. Microsoft had previously depreciated and eliminated this feature for the 64-bit version of SQL Server.</p>
<p>They recently reversed their decision, and claim no new plans to depreciate this provider. However, the link is slightly hidden. Here it is: <a title="64-Bit OLEDB Provider for ODBC (MSDASQL)" href="http://www.microsoft.com/downloads/details.aspx?FamilyID=000364db-5e8b-44a8-b9be-ca44d18b059b&amp;displaylang=en" target="_blank">http://www.microsoft.com/downloads/details.aspx?FamilyID=000364db-5e8b-44a8-b9be-ca44d18b059b&amp;displaylang=en</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.discreteinformation.com/2009/05/link-mysql-to-64-bit-ms-sql-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
