Saturday, December 27, 2003
Monday, December 22, 2003
Microsoft Office 2003 Install/Setup, A- Grade
Microsoft Office 2003 Install/Setup, A- Grade
I turned on my computer this morning and something strange happened, my Outlook and Excel were just waaaay too slow. I have a superfast machine with over a gig of RAM, should be no problems. I started poking around and realized that I was still running the Office 2003 beta! So I inserted the RTM Office 2003 DVD and held my breath.
Well it did a great job. Install prompted me to uninstall automatically the old version. (This is where I got scared, I have tons of settings I wanted to keep.) Installation offered me the option of a “complete” install which is cool. After the install was complete (no reboot required), all of my settings were restored to where they were when I left, except the email signature (which was preserved but not set up by default after installation.) I had a ton of custom settings, so this was quite impressive.
Overall Setup/Installation gets an A-. Good job MSFT.
Saturday, December 20, 2003
Open Letter to Real Networks CEO
Open Letter to Real Networks CEO
Dear Robert Glaser,
I use WinAmp to listen to my illegal MP3s. I don’t use Microsoft’s Media Player because it sucks. Nor do I use your crappy software because, well it sucks. Big time. (While on the topic of your sucky software, what is the deal with the installation, you have to fill out my life history, etc.)
Your lawsuit is a sham. I did a find and replace with “Netscape” and “Real Networks” in the court papers you filed and guess what? I know why your company is suing Microsoft, it is because you have a personal vendetta against Bill Gates (are you mad that he yelled at you in that meeting in 1995 and you quit your well paying MS job?) . Get real.
How about this one? Build better software and drop the damn lawsuit.
Sincerely,
Stephen Forte
Friday, December 19, 2003
Exception Handling in Yukon Transactions
Exception Handling in Yukon Transactions
Ok, it is Friday, so an easy one to digest, but quite powerful. Yukon has made a major improvement in Error Handling inside of TSQL transactions. You can now catch Transaction Abort Errors using the TRY / CATCH model without any loss of the transaction context. This makes me very happy. The syntax is here:
BEGIN TRY
sql statement
END TRY
BEGIN CATCH TRAN_ABORT
sql statement
END CATCH
See my article on SQLJunkies.com.
Thursday, December 18, 2003
New Data Types in Yukon
New Data Types in Yukon
There are a few very cool new types. The most noticeable are categorized as: DateTime types, varchar(max), and XML. There are a few datetime datatypes, but the most interesting new DateTime datatypes are the UtcDateTime, Date and Time types The UtcDateTime datatype is time zone aware and is used in scenarios where the server and clients span multiple time zones. It uses an expanded range (from 1 AD for 9999 AD) and precision (100 nanoseconds.) The Date datatype is useful when you just want to store the simple date and has the same expanded range. The Time is a new datatype for Time only and has expanded precision (100 nanoseconds.) Varchar(Max) is an extension to varchar, nvarchar, varbinary that will store data up to 2GB and is an alternative to text/ntext/image. It uses the Uses MAX size specifier, like so:
CREATE TABLE TablewithMaxColumn
(Customer_Id int, CustomerLifeStrory varbinary(max))
All string functions operate on varchar(max), you can use the TSQL SUBSTRING to read chunks and the UPDATE statement has been enhanced to support update of CHUNKS.
To accommodate the growing importance of XML Yukon includes an XML datatype. In the past developers would store XML in a varchar or text/ntext field. That was not optimal since the XML was not in its native format and you could not query its contents efficiently. The new datatype allows developers to store XML in its native format (well actually it is stored in a BLOB field) and gives you the ability to via XQuery to query parts of the XML field.
The XML datatype is a full blown TSQL citizen, able to have table columns and participate in a CAST or CONVERT statement. You can even use the FOR XML statement to convert tabular data into XML from a SQL query:
DECLARE @xmlData AS XML
SET @xmlData = (SELECT * From Customers FOR XML AUTO, TYPE)
SELECT @xmlData
As expected the results of a row look like this:
<Customers CustomerID="ALFKI" CompanyName="Alfreds Futterkiste" ContactName="Maria Anders" ContactTitle="Sales Representative" Address="Obere Str. 57" City="Berlin" PostalCode="12209" Country="Germany" Phone="030-0074321" Fax="030-0076545"/>
You can also insert this XML data into a new XML field in a table and have data validations based on XSD be enforced by Yukon. Pretty cool stuff.
See my article on SQLJunkies.com.
Wednesday, December 17, 2003
Common Table Expressions in Yukon
Common Table Expressions in Yukon
A Common Table Expression closely resembles a non-persistent view. A CTE is a temporary named result set that you define in your query that will be used by the FROM clause of the query. Each CTE is only defined once (but can be referred to as many time as it is in scope) and lives for as long as the query lives. CTEs can also be used to perform recursive operations. Here is the syntax to create a CTE:
With <name of your CTE>(<column names>)
As
(
<actual query>
)
Select * from <name of your CTE>
An example of a simple CTE is shown here:
With LondonCustomersCTE
As
(Select * From Customers Where City='London')
Select * From LondonCustomersCTE
Here is an example where we get a list of all the count of Customers’ orders in the orders table as a CTE and then a simple inner join with the Customer’s table to return the full name of the customer. (Sure this can be done without a CTE, but think about the ease of aggregating in the CTE only, it makes your code much easier to deal with.)
The code is here:
With CustomerOrderCountCTE(CustomerID, OrderCount)
As
(
select CustomerID, Count(*)
from orders
group by CustomerID
)
Select CU.CompanyName, City, COC.OrderCount
From Customers As CU Inner Join CustomerOrderCountCTE As COC
on CU.CustomerID = COC.CustomerID
Order By COC.OrderCount Desc
The true power of CTEs are when you use then recursively. A recursive CTE is constructed from a minimum of two queries, the first or Anchor Member (AM) is a non-recursive query and the send is the recursive query or the Recursive Member (RM). The AM and RM are separated by a UNION ALL statement. Here is the syntax:
With SimpleRecursive( field names)
As
(
<Select Statement for Anchor Member>
Union All
<Select Statement for the Recursive Memember>
)
Select * From SimpleRecursive
See my article on SQLJunkies.com.
Tuesday, December 16, 2003
TOP Enhancements in Yukon
TOP Enhancements in Yukon
In previous versions of SQL Server TOP allowed you to limit the number of rows returned as a number or percentage in Select Queries. I use this all the time. It has gotten more flexible in Yukon where TOP can be used in Delete, Update and Insert queries. What is even cooler is that Yukon will allow you to specify the number of rows (or percent) by using variables or subqueries. I love the ability to dynamically set the TOP, so much that I have started writing Stored Procedures that accept a NumberofRows parameter like so:
Create Procedure usp_SEL_ReturnTopOrders
@NumberofRows int
As
Select TOP (@NumberofRows) OrderID
From Orders
Order By OrderID
Executing the stored procedure is easy, just pass in how many records that you want (in this case it is 100):
usp_SEL_ReturnTopOrders 100
Using a subquery can be very powerful when you are doing things on the fly. A real simple example to demonstrate the concept is show here, we are getting the TOP n customers based on how many records we have in our Employees table:
Select TOP (Select Count(*) from Employees) *
From Orders
See my article on SQLJunkies.com.
Monday, December 15, 2003
PIVOT Data in Yukon (RIP Case and Rozenshtein)
PIVOT Data in Yukon (RIP Case and Rozenshtein)
Let’s face it, users usually want to see data in tabular format, which is a bit of a challenge when we usually store data in a highly relational form. PIVOT is a new TSQL operator that you can specify in your FROM clause to rotate rows into columns and create a traditional “Crosstab” query without using CASE, Rozenshtein or subqueries. You have always been able to do this easily in Access with Pivot and Transform, but SQL Server was always a step behind.
Using PIVOT is easy. First in your select statement you need to specify the values you want to pivot on, in the following example, we will use the Year of the Order. Our FROM clause looks normal except for the PIVOT part. The PIVOT statement creates the value we plan on showing in the rows of the newly created columns, in this case I am using the aggregate SUM of the TotalAmount (a calculated field in our FROM clause). Then we have to use the FOR operator to list the values we are going to Pivot on in the OrdersYear column. The example is shown here:
SELECT CustomerID, [1996] AS 'Y1996', [1997] AS 'Y1997', [1998] AS 'Y1998', [1999] as 'Y1999'
FROM
(SELECT CustomerID,OD.UnitPrice * OD.Quantity - OD.Discount AS TotalAmt,
Year(dbo.Orders.OrderDate) as OrdersYear
FROM dbo.Orders INNER JOIN dbo.[Order Details] As OD
ON dbo.Orders.OrderID = OD.OrderID)
As Orders
PIVOT
(
SUM(TotalAmt)
FOR OrdersYear IN([1996], [1997], [1998], [1999])
) AS XTabData
Order BY CustomerID
The results look like this:
|
CustomerID |
Y1996 |
Y1997 |
Y1998 |
|
ALFKI |
NULL |
2293.25 |
2301.9 |
|
ANATR |
88.8 |
799.75 |
514.4 |
|
ANTON |
403.2 |
6451.15 |
660 |
|
AROUT |
1379 |
6588.4 |
5838.4 |
|
BERGS |
4324.4 |
14532.25 |
8108.5 |
|
BLAUS |
NULL |
1079.8 |
2160 |
|
BLONP |
9986.2 |
8371.05 |
730 |
|
BOLID |
982 |
4035.3 |
279.8 |
|
BONAP |
4202.35 |
12460.7 |
7184.7 |
That is all there is to it. Of course this is a real simple example to show you the new concept, you can then of course get more sophisticated aggregates and even use Common Table Expressions in the FROM clause. Also you can use the UNPIVOT operator to normalize data that is already pivoted.
See my article on SQLJunkies.com.
|