Showing posts with label table. Show all posts
Showing posts with label table. Show all posts

Friday, March 30, 2012

question with trigger

i have a table which has columns scheduledrent,actualrent beside other columns.
the actual rent is based on some calculations but uses scheduledrent for the calculations.

everytime there is a change to scheduledrent, the actualrent should also change. so if i write a trigger saying
if updated(scheduledrent)
do some calculations and change the actualrent..using an update stmt.

would it make the change only for that row or for all the rows in the table? if it does it for all the rows, how do i make it apply only to that row. how should i have my update stmt in such a case. my primarykey is a combination of 4 rows. so can i get all the 4 values into some variables and while i do the update do it on that condition ? or is there any easier way of doing it.

thanks.
D.Inside the trigger code you have access to a logical table named "inserted". You can run your update logic with that table and it will only update the rows that were updated. The logical table "inserted" is available for update triggers and, naturally enough, insert triggers.

The logical table "deleted" is available for delete triggers and shows the records to be deleted. In an update trigger the "deleted" table shows the original values before they are to be changed.|||ok it works if i change it to inserted.
have one q though. i have 10 ppl accessing the db at any time. so if all of them make an update to the db (not to the same record though) each one will have an entry in the logical inserted table. so how would the system differentiate between them, since they all login to sql server through the same asp.net account.

thanks for the tip.|||The inserted logical table will only be for the record(s) that triggered that specific update. So everyone will have their own inserted logical tables and won't be stepping on one another.|||oh so sql server creates an inserted table for each user ?
but how does the sql server differentiate between users ?

lets say userA logged onto mysite and made an update to a row. the row gets inserted into the inserted table. userB also logs in at the same time and makes an update to another row. the new row also gets into the inserted table. now both these users are logged into the sqlserver through the same ASP.NET account. so how does sql server differentiate betwen userA and userB and their updated rows?

thanks again.|||It's a "logical" table meaning that it acts like a table but isn't really one. It is there to allow the trigger code to inspect the state of the old and new records so that the trigger code can take whatever action is appropriate. The logical table inside one trigger event isn't visible or accessible to the logical table in any other trigger event, even for the same user logged on multiple times simultaneously updating different record(s).|||i dont think i have understood completely. do you know any article that xplains in detail how the inserted table actually works...?
thanks anyway. will leave it for now. hope it works. will get back incase i have any prb.

thanks McMurdoStation.sql

Question with Flattening / Denormalizing a Hiearchy Dynamically

Hello,

I've been trying to figure out a way to handle flattening a Reports To hierarchy table dyamically. The end result I need is this. Example assumes a two person / two level hiearchy. Emplid of 1 is the CEO, Emplid of 2 is the direct report. I am unable to get this result.

Emplid Reports To Level 1 Emplid Reports To Level 2 Id

1 1

2 1 2

Much kudos to Adam Machanic and Itzik Ben-Gan for their code samples and articles (links below). They have gotten me quite far but I am not there yet.

http://searchsqlserver.techtarget.com/tip/1,289483,sid87_gci1107414,00.html

http://www.sqlmag.com/Article/ArticleID/94268/sql_server_94268.html

After reading these articles I have been able to find out the materialized path and the level in which an employee resides in the Reports To hierarchy. Here is what the data looks like after the recursive CTE (I'll put the code down at the bottom of the blog)

Listing 1:

Emplid Level thePath (Materialized reporting path)

1 1 .1

2 2 .1.2

I have then dynamically invoked the PIVOT command via a stored procedure thanks to help from Itzik again (http://www.sqlmag.com/Article/ArticleID/94268/sql_server_94268.html). This is allowing me to get a result like this below, but it only has the column for the level in the hierarchy in which the employee resides popululated and not the columns for the levels about the employee (Emplid 2 should have a 1 in the second column) See result below.

Listing 2:

Emplid Reports To Level 1 Emplid Reports To Level 2 Id

1 1

2 2

Is there a way to populate the second column for Emplid 2 all in one shot? Right now I am thinking I'll have to land the result of pivot function call to a table and then parse out the thePath column and update the unpopulated columns that way. It seems like this is too complicated. Any suggestions?

Thanks in advance!

Sean

Code is below. Below has a view that contains my recursive CTE and a select from the view (Like Listing 1 Results). The function that dynamically executes the pivot function and then the function call (Like Listing 2 Results).

--Recursive CTE view definition

Use AdventureWorks
;

create view HumanResources.V_EMP_HIER
as

WITH EmployeeCTE
AS
(
SELECT
EmployeeID,
1 AS Level,
CAST('.' + CAST(EmployeeID AS VARCHAR(10)) + '.'
AS VARCHAR(MAX)) AS thePath
FROM HumanResources.Employee
WHERE ManagerID IS NULL

UNION ALL

SELECT
E.EmployeeID,
x.Level + 1 AS Level,
x.thePath + '.' + CONVERT(VARCHAR(MAX), E.EmployeeID) AS thePath
FROM HumanResources.Employee E
JOIN EmployeeCTE x ON x.EmployeeID = E.ManagerID
)
SELECT
EmployeeID,
Level,
thePath
FROM EmployeeCTE

;
GO

--Snipet to list the hierarchy
select
EmployeeID,
Level,
thePath,
REPLICATE(' | ', Level) + CONVERT(varchar,EmployeeID) AS EmpSort

FROM
HumanResources.V_EMP_HIER
order by thePath
;

Dynamic Pivot Function. Thanks Itzik!

Use AdventureWorks
;

IF EXISTS
(SELECT * FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[usp_pivot]')
AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[usp_pivot]
;
GO

CREATE PROC [dbo].[usp_pivot]
@.schema_name AS sysname = N'dbo', -- schema of table/view
@.object_name AS sysname = NULL, -- name of table/view
@.on_rows AS sysname = NULL, -- group by column
@.on_cols AS sysname = NULL, -- rotation column
@.agg_func AS NVARCHAR(12) = N'MAX', -- aggregate function
@.agg_col AS sysname = NULL -- aggregate column
AS

DECLARE
@.object AS NVARCHAR(600),
@.sql AS NVARCHAR(MAX),
@.cols AS NVARCHAR(MAX),
@.newline AS NVARCHAR(2),
@.msg AS NVARCHAR(500);

SET @.newline = NCHAR(13) + NCHAR(10);
SET @.object = QUOTENAME(@.schema_name) + N'.' + QUOTENAME(@.object_name);

-- Check for missing input
IF @.schema_name IS NULL
OR @.object_name IS NULL
OR @.on_rows IS NULL
OR @.on_cols IS NULL
OR @.agg_func IS NULL
OR @.agg_col IS NULL
BEGIN
SET @.msg = N'Missing input parameters: '
+ CASE WHEN @.schema_name IS NULL THEN N'@.schema_name;' ELSE N'' END
+ CASE WHEN @.object_name IS NULL THEN N'@.object_name;' ELSE N'' END
+ CASE WHEN @.on_rows IS NULL THEN N'@.on_rows;' ELSE N'' END
+ CASE WHEN @.on_cols IS NULL THEN N'@.on_cols;' ELSE N'' END
+ CASE WHEN @.agg_func IS NULL THEN N'@.agg_func;' ELSE N'' END
+ CASE WHEN @.agg_col IS NULL THEN N'@.agg_col;' ELSE N'' END
RAISERROR(@.msg, 16, 1);
RETURN;
END

-- Allow only existing table or view name as input object
IF COALESCE(OBJECT_ID(@.object, N'U'),
OBJECT_ID(@.object, N'V')) IS NULL
BEGIN
SET @.msg = N'%s is not an existing table or view in the database.';
RAISERROR(@.msg, 16, 1, @.object);
RETURN;
END

-- Verify that column names specified in @.on_rows, @.on_cols, @.agg_col exist
IF COLUMNPROPERTY(OBJECT_ID(@.object), @.on_rows, 'ColumnId') IS NULL
OR COLUMNPROPERTY(OBJECT_ID(@.object), @.on_cols, 'ColumnId') IS NULL
OR COLUMNPROPERTY(OBJECT_ID(@.object), @.agg_col, 'ColumnId') IS NULL
BEGIN
SET @.msg = N'%s, %s and %s must'
+ N' be existing column names in %s.';
RAISERROR(@.msg, 16, 1, @.on_rows, @.on_cols, @.agg_col, @.object);
RETURN;
END

-- Verify that @.agg_func is in a known list of functions
-- Add to list as needed and adjust @.agg_func size accordingly
IF @.agg_func NOT IN
(N'AVG', N'COUNT', N'COUNT_BIG', N'SUM', N'MIN', N'MAX',
N'STDEV', N'STDEVP', N'VAR', N'VARP')
BEGIN
SET @.msg = N'%s is an unsupported aggregate function.';
RAISERROR(@.msg, 16, 1, @.agg_func);
RETURN;
END

-- Construct column list
SET @.sql =
N'SET @.result = ' + @.newline +
N' STUFF(' + @.newline +
N' (SELECT N'','' + '
+ N'QUOTENAME(pivot_col) AS [text()]' + @.newline +
N' FROM (SELECT DISTINCT('
+ QUOTENAME(@.on_cols) + N') AS pivot_col' + @.newline +
N' FROM ' + @.object + N') AS DistinctCols' + @.newline +
N' ORDER BY pivot_col' + @.newline +
N' FOR XML PATH('''')),' + @.newline +
N' 1, 1, N'''');'

EXEC sp_executesql
@.stmt = @.sql,
@.params = N'@.result AS NVARCHAR(MAX) OUTPUT',
@.result = @.cols OUTPUT;

-- Check @.cols for possible SQL injection attempt
IF UPPER(@.cols) LIKE UPPER(N'%0x%')
OR UPPER(@.cols) LIKE UPPER(N'%;%')
OR UPPER(@.cols) LIKE UPPER(N'%''%')
OR UPPER(@.cols) LIKE UPPER(N'%--%')
OR UPPER(@.cols) LIKE UPPER(N'%/*%*/%')
OR UPPER(@.cols) LIKE UPPER(N'%EXEC%')
OR UPPER(@.cols) LIKE UPPER(N'%xp[_]%')
OR UPPER(@.cols) LIKE UPPER(N'%sp[_]%')
OR UPPER(@.cols) LIKE UPPER(N'%SELECT%')
OR UPPER(@.cols) LIKE UPPER(N'%INSERT%')
OR UPPER(@.cols) LIKE UPPER(N'%UPDATE%')
OR UPPER(@.cols) LIKE UPPER(N'%DELETE%')
OR UPPER(@.cols) LIKE UPPER(N'%TRUNCATE%')
OR UPPER(@.cols) LIKE UPPER(N'%CREATE%')
OR UPPER(@.cols) LIKE UPPER(N'%ALTER%')
OR UPPER(@.cols) LIKE UPPER(N'%DROP%')
-- Look for other possible strings used in SQL injection here
BEGIN
SET @.msg = N'Possible SQL injection attempt.';
RAISERROR(@.msg, 16, 1);
RETURN;
END

-- Create the PIVOT query
SET @.sql =
N'SELECT *' + @.newline +
N'FROM' + @.newline +
N' ( SELECT ' + @.newline +
N' ' + QUOTENAME(@.on_rows) + N',' + @.newline +
N' ' + QUOTENAME(@.on_cols) + N' AS pivot_col,' + @.newline +
N' ' + QUOTENAME(@.agg_col) + N' AS agg_col' + @.newline +
N' FROM ' + @.object + @.newline +
N' ) AS PivotInput' + @.newline +
N' PIVOT' + @.newline +
N' ( ' + @.agg_func + N'(agg_col)' + @.newline +
N' FOR pivot_col' + @.newline +
N' IN(' + @.cols + N')' + @.newline +
N' ) AS PivotOutput;';

EXEC sp_executesql @.sql;
GO

Call of the function that flattens the hierarchy, but doesn't populate of of the reporting level columns.

Use AdventureWorks
;

EXEC dbo.usp_pivot
@.schema_name = N'HumanResources',
@.object_name = N'V_EMP_HIER',
@.on_rows = N'EmployeeID',
@.on_cols = N'Level',
@.agg_func = N'MAX',
@.agg_col = N'EmployeeID';
;

Sean, we talked at the Microsoft BI Conference last week in Seattle and you were looking for some help on this posting. I’ve followed up with an internal alias that had some T-SQL gurus on it and hopefully one of the following solutions may help you get going in the right direction. Alternatively, you could consider using Microsoft SQL Server Analysis Services (AS) for this kind of reporting which may make it easier and faster. There is the notion of Parent\Child dimensions built into AS.

Good Luck!

-- Scott

-

<Header clipped>

Perhaps this would help…

set nocount on;

use northwind;

go

-- create helper function fn_nums

-- returning an auxiliary table of numbers

if object_id('dbo.fn_nums', 'if') is not null

drop function dbo.fn_nums;

go

create function dbo.fn_nums(@.max as int)

returns table as return

with

c0 as(select 0 as const union all select 0),

c1 as(select 0 as const from c0 as a, c0 as b),

c2 as(select 0 as const from c1 as a, c1 as b),

c3 as(select 0 as const from c2 as a, c2 as b),

c4 as(select 0 as const from c3 as a, c3 as b),

c5 as(select 0 as const from c4 as a, c4 as b),

c6 as(select 0 as const from c5 as a, c5 as b)

select top(@.max) row_number()

over(order by const) as n

from c6;

go

-- create helper function fn_split

-- splitting a string

if object_id('dbo.fn_split') is not null

drop function dbo.fn_split;

go

create function dbo.fn_split

(@.string varchar(max), @.separator char(1) = ',') returns table

as

return

select

n - len(replace(left(array, n), @.separator, '')) + 1 as pos,

substring(array, n,

charindex(@.separator, array + @.separator, n) - n) as element

from (select @.string as array) as d

join dbo.fn_nums(900)

on n <= len(array)

and substring(@.separator + array, n, 1) = @.separator;

go

-- Solution query

with empscte as

(

select employeeid, reportsto,

'.' + cast(employeeid as varchar(max)) + '.' as thepath

from employees

where reportsto is null

union all

select sub.employeeid, sub.reportsto,

mgr.thepath + cast(sub.employeeid as varchar(max)) + '.'

from empscte as mgr

join employees as sub

on sub.reportsto = mgr.employeeid

)

select *

from (select employeeid, pos, element as managerid

from empscte as e

cross apply dbo.fn_split(stuff(e.thepath, 1, 1, ''), '.') as s) as d

pivot(max(managerid) for pos in([1],[2],[3],[4],[5]/*add more levels here*/)) as p;

-

From: Ty Balascio
Sent: Monday, May 14, 2007 11:09 AM
Subject: RE: T-SQL Question from customer

I was part of a Usenet thread on this many years ago. Here was the preferred solution.

<paste>

-- If a node's parent is 0, then it's the root node

-- Each node has a unique id and a name

CREATE TABLE Tree

(

parent INT NOT NULL DEFAULT 0 CHECK (parent >= 0),

node INT NOT NULL CHECK (node > 0) PRIMARY KEY,

name VARCHAR(20) NOT NULL

)

GO

-- UDF to return all descendants of a given node

-- Node is identified by its id number

-- Distance is the number of links between two nodes

CREATE FUNCTION Descendants(@.root_node INT)

RETURNS @.nodes TABLE

(node INT NOT NULL PRIMARY KEY CHECK (node > 0),

name VARCHAR(20) NOT NULL,

distance INT NOT NULL CHECK (distance >= 0))

AS

BEGIN

IF NOT EXISTS (SELECT * FROM Tree WHERE node = @.root_node)

RETURN

DECLARE @.distance INT,

@.next_distance INT

SELECT @.distance = 0,

@.next_distance = 1

INSERT INTO @.nodes (node, name, distance)

SELECT node, name, @.distance

FROM Tree

WHERE node = @.root_node

WHILE EXISTS (SELECT * FROM @.nodes WHERE distance = @.distance)

BEGIN

INSERT INTO @.nodes (node, name, distance)

SELECT T.node, T.name, @.next_distance

FROM @.nodes AS N

INNER JOIN

Tree AS T

ON N.distance = @.distance AND

N.node = T.parent

SELECT @.distance = @.next_distance,

@.next_distance = @.next_distance + 1

END

RETURN

END

GO

-- Sample tree

INSERT INTO Tree (parent, node, name)

SELECT 0, 1, 'A' -- root node

UNION ALL

SELECT 1, 2, 'B'

UNION ALL

SELECT 1, 3, 'C'

UNION ALL

SELECT 2, 4, 'D'

UNION ALL

SELECT 2, 5, 'E'

UNION ALL

SELECT 3, 6, 'F'

UNION ALL

SELECT 5, 7, 'G'

UNION ALL

SELECT 5, 8, 'H'

UNION ALL

SELECT 5, 9, 'I'

-- All nodes

SELECT *

FROM Descendants(1)

ORDER BY distance, node

-- All nodes from node id 2 (named B)

SELECT *

FROM Descendants(2)

ORDER BY distance, node

</paste>

|||

Below are simpler and more efficient solutions. You don't really need the UDFs or PIVOT clause and other objects. You can do it with a single CTE. The level can be encoded in the hierarchy path so it is just a matter of decoding it the easiest way.

Code Snippet

-- Using Northwind Employees table:

with EmpTree
as
(
select e.EmployeeID, cast(cast(e.EmployeeID as binary(4)) as varbinary(max)) as EmpHier
from Northwind.dbo.Employees as e
where e.ReportsTo is null
union all
select c.EmployeeID, cast(p.EmpHier + cast(c.EmployeeID as binary(4)) as varbinary(max))
from EmpTree as p
join Northwind.dbo.Employees as c
on c.ReportsTo = p.EmployeeID
)
select EmployeeID
, nullif(cast(substring(EmpHier, 1, 4) as int), 0) as lvl_1
, nullif(cast(substring(EmpHier, 5, 4) as int), 0) as lvl_2
, nullif(cast(substring(EmpHier, 9, 4) as int), 0) as lvl_3
, nullif(cast(substring(EmpHier, 13, 4) as int), 0) as lvl_4
, nullif(cast(substring(EmpHier, 17, 4) as int), 0) as lvl_5
, nullif(cast(substring(EmpHier, 21, 4) as int), 0) as lvl_6
, nullif(cast(substring(EmpHier, 25, 4) as int), 0) as lvl_7
, nullif(cast(substring(EmpHier, 29, 4) as int), 0) as lvl_8
, nullif(cast(substring(EmpHier, 33, 4) as int), 0) as lvl_9
, nullif(cast(substring(EmpHier, 37, 4) as int), 0) as lvl_10
from EmpTree;


-- Using AdventureWorks Employee table:

with EmpTree
as
(
select e.EmployeeID, cast(cast(e.EmployeeID as binary(4)) as varbinary(max)) as EmpHier
from AdventureWorks.HumanResources.Employee as e
where e.ManagerID is null
union all
select c.EmployeeID, cast(p.EmpHier + cast(c.EmployeeID as binary(4)) as varbinary(max))
from EmpTree as p
join AdventureWorks.HumanResources.Employee as c
on c.ManagerID = p.EmployeeID
)
select EmployeeID
, nullif(cast(substring(EmpHier, 1, 4) as int), 0) as lvl_1
, nullif(cast(substring(EmpHier, 5, 4) as int), 0) as lvl_2
, nullif(cast(substring(EmpHier, 9, 4) as int), 0) as lvl_3
, nullif(cast(substring(EmpHier, 13, 4) as int), 0) as lvl_4
, nullif(cast(substring(EmpHier, 17, 4) as int), 0) as lvl_5
, nullif(cast(substring(EmpHier, 21, 4) as int), 0) as lvl_6
, nullif(cast(substring(EmpHier, 25, 4) as int), 0) as lvl_7
, nullif(cast(substring(EmpHier, 29, 4) as int), 0) as lvl_8
, nullif(cast(substring(EmpHier, 33, 4) as int), 0) as lvl_9
, nullif(cast(substring(EmpHier, 37, 4) as int), 0) as lvl_10
from EmpTree;

|||

Scott, Ty and Umachandar.

Thank you all for your options. The solutions give us what we need and a few alternatives too.

I really appreciate you time and efforts.


Sean

|||

Two other options that were forwarded to me:

--

Here's another option:

with empscte as
(
select employeeid, managerid, 1 as lvl,
cast(employeeid as varbinary(max)) as binpath
from humanresources.employee
where managerid is null

union all

select sub.employeeid, sub.managerid, mgr.lvl + 1,
mgr.binpath + cast(sub.employeeid as binary(4))
from empscte as mgr
join humanresources.employee as sub
on sub.managerid = mgr.employeeid
)
select replicate(' | ', lvl-1) + cast(employeeid as varchar(10)) as emp,
nullif(0+substring(binpath, 1, 4), 0) as l1,
nullif(0+substring(binpath, 5, 4), 0) as l2,
nullif(0+substring(binpath, 9, 4), 0) as l3,
nullif(0+substring(binpath, 13, 4), 0) as l4,
nullif(0+substring(binpath, 17, 4), 0) as l5,
nullif(0+substring(binpath, 21, 4), 0) as l6,
/* add more levels here if needed */
lvl
from empscte
order by binpath;

Itzik

Another response – this one from Adam.

Maybe I'm missing something--how dynamic do you want this to be? Can you use placeholder columns for levels that may not be there? If so, wouldn't something like the following work fine (you can run it in AW):

with emps as

(

select

e.employeeid,

null as ReportsToLevel1,

null as ReportsToLevel2,

null as ReportsToLevel3,

null as ReportsToLevel4,

null as ReportsToLevel5,

null as ReportsToLevel6,

null as ReportsToLevel7,

null as ReportsToLevel8,

1 as theLevel

from humanresources.employee e

where managerid is null

union all

select

e.employeeid,

case theLevel when 1 then e.managerid else x.ReportsToLevel1 end,

case theLevel when 2 then e.managerid else x.ReportsToLevel2 end,

case theLevel when 3 then e.managerid else x.ReportsToLevel3 end,

case theLevel when 4 then e.managerid else x.ReportsToLevel4 end,

case theLevel when 5 then e.managerid else x.ReportsToLevel5 end,

case theLevel when 6 then e.managerid else x.ReportsToLevel6 end,

case theLevel when 7 then e.managerid else x.ReportsToLevel7 end,

case theLevel when 8 then e.managerid else x.ReportsToLevel8 end,

theLevel + 1 as theLevel

from humanresources.employee e

join emps x on x.employeeid = e.managerid

)

select *

from emps

Question with Flattening / Denormalizing a Hiearchy Dynamically

Hello,

I've been trying to figure out a way to handle flattening a Reports To hierarchy table dyamically. The end result I need is this. Example assumes a two person / two level hiearchy. Emplid of 1 is the CEO, Emplid of 2 is the direct report. I am unable to get this result.

Emplid Reports To Level 1 Emplid Reports To Level 2 Id

1 1

2 1 2

Much kudos to Adam Machanic and Itzik Ben-Gan for their code samples and articles (links below). They have gotten me quite far but I am not there yet.

http://searchsqlserver.techtarget.com/tip/1,289483,sid87_gci1107414,00.html

http://www.sqlmag.com/Article/ArticleID/94268/sql_server_94268.html

After reading these articles I have been able to find out the materialized path and the level in which an employee resides in the Reports To hierarchy. Here is what the data looks like after the recursive CTE (I'll put the code down at the bottom of the blog)

Listing 1:

Emplid Level thePath (Materialized reporting path)

1 1 .1

2 2 .1.2

I have then dynamically invoked the PIVOT command via a stored procedure thanks to help from Itzik again (http://www.sqlmag.com/Article/ArticleID/94268/sql_server_94268.html). This is allowing me to get a result like this below, but it only has the column for the level in the hierarchy in which the employee resides popululated and not the columns for the levels about the employee (Emplid 2 should have a 1 in the second column) See result below.

Listing 2:

Emplid Reports To Level 1 Emplid Reports To Level 2 Id

1 1

2 2

Is there a way to populate the second column for Emplid 2 all in one shot? Right now I am thinking I'll have to land the result of pivot function call to a table and then parse out the thePath column and update the unpopulated columns that way. It seems like this is too complicated. Any suggestions?

Thanks in advance!

Sean

Code is below. Below has a view that contains my recursive CTE and a select from the view (Like Listing 1 Results). The function that dynamically executes the pivot function and then the function call (Like Listing 2 Results).

--Recursive CTE view definition

Use AdventureWorks
;

create view HumanResources.V_EMP_HIER
as

WITH EmployeeCTE
AS
(
SELECT
EmployeeID,
1 AS Level,
CAST('.' + CAST(EmployeeID AS VARCHAR(10)) + '.'
AS VARCHAR(MAX)) AS thePath
FROM HumanResources.Employee
WHERE ManagerID IS NULL

UNION ALL

SELECT
E.EmployeeID,
x.Level + 1 AS Level,
x.thePath + '.' + CONVERT(VARCHAR(MAX), E.EmployeeID) AS thePath
FROM HumanResources.Employee E
JOIN EmployeeCTE x ON x.EmployeeID = E.ManagerID
)
SELECT
EmployeeID,
Level,
thePath
FROM EmployeeCTE

;
GO

--Snipet to list the hierarchy
select
EmployeeID,
Level,
thePath,
REPLICATE(' | ', Level) + CONVERT(varchar,EmployeeID) AS EmpSort

FROM
HumanResources.V_EMP_HIER
order by thePath
;

Dynamic Pivot Function. Thanks Itzik!

Use AdventureWorks
;

IF EXISTS
(SELECT * FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[usp_pivot]')
AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[usp_pivot]
;
GO

CREATE PROC [dbo].[usp_pivot]
@.schema_name AS sysname = N'dbo', -- schema of table/view
@.object_name AS sysname = NULL, -- name of table/view
@.on_rows AS sysname = NULL, -- group by column
@.on_cols AS sysname = NULL, -- rotation column
@.agg_func AS NVARCHAR(12) = N'MAX', -- aggregate function
@.agg_col AS sysname = NULL -- aggregate column
AS

DECLARE
@.object AS NVARCHAR(600),
@.sql AS NVARCHAR(MAX),
@.cols AS NVARCHAR(MAX),
@.newline AS NVARCHAR(2),
@.msg AS NVARCHAR(500);

SET @.newline = NCHAR(13) + NCHAR(10);
SET @.object = QUOTENAME(@.schema_name) + N'.' + QUOTENAME(@.object_name);

-- Check for missing input
IF @.schema_name IS NULL
OR @.object_name IS NULL
OR @.on_rows IS NULL
OR @.on_cols IS NULL
OR @.agg_func IS NULL
OR @.agg_col IS NULL
BEGIN
SET @.msg = N'Missing input parameters: '
+ CASE WHEN @.schema_name IS NULL THEN N'@.schema_name;' ELSE N'' END
+ CASE WHEN @.object_name IS NULL THEN N'@.object_name;' ELSE N'' END
+ CASE WHEN @.on_rows IS NULL THEN N'@.on_rows;' ELSE N'' END
+ CASE WHEN @.on_cols IS NULL THEN N'@.on_cols;' ELSE N'' END
+ CASE WHEN @.agg_func IS NULL THEN N'@.agg_func;' ELSE N'' END
+ CASE WHEN @.agg_col IS NULL THEN N'@.agg_col;' ELSE N'' END
RAISERROR(@.msg, 16, 1);
RETURN;
END

-- Allow only existing table or view name as input object
IF COALESCE(OBJECT_ID(@.object, N'U'),
OBJECT_ID(@.object, N'V')) IS NULL
BEGIN
SET @.msg = N'%s is not an existing table or view in the database.';
RAISERROR(@.msg, 16, 1, @.object);
RETURN;
END

-- Verify that column names specified in @.on_rows, @.on_cols, @.agg_col exist
IF COLUMNPROPERTY(OBJECT_ID(@.object), @.on_rows, 'ColumnId') IS NULL
OR COLUMNPROPERTY(OBJECT_ID(@.object), @.on_cols, 'ColumnId') IS NULL
OR COLUMNPROPERTY(OBJECT_ID(@.object), @.agg_col, 'ColumnId') IS NULL
BEGIN
SET @.msg = N'%s, %s and %s must'
+ N' be existing column names in %s.';
RAISERROR(@.msg, 16, 1, @.on_rows, @.on_cols, @.agg_col, @.object);
RETURN;
END

-- Verify that @.agg_func is in a known list of functions
-- Add to list as needed and adjust @.agg_func size accordingly
IF @.agg_func NOT IN
(N'AVG', N'COUNT', N'COUNT_BIG', N'SUM', N'MIN', N'MAX',
N'STDEV', N'STDEVP', N'VAR', N'VARP')
BEGIN
SET @.msg = N'%s is an unsupported aggregate function.';
RAISERROR(@.msg, 16, 1, @.agg_func);
RETURN;
END

-- Construct column list
SET @.sql =
N'SET @.result = ' + @.newline +
N' STUFF(' + @.newline +
N' (SELECT N'','' + '
+ N'QUOTENAME(pivot_col) AS [text()]' + @.newline +
N' FROM (SELECT DISTINCT('
+ QUOTENAME(@.on_cols) + N') AS pivot_col' + @.newline +
N' FROM ' + @.object + N') AS DistinctCols' + @.newline +
N' ORDER BY pivot_col' + @.newline +
N' FOR XML PATH('''')),' + @.newline +
N' 1, 1, N'''');'

EXEC sp_executesql
@.stmt = @.sql,
@.params = N'@.result AS NVARCHAR(MAX) OUTPUT',
@.result = @.cols OUTPUT;

-- Check @.cols for possible SQL injection attempt
IF UPPER(@.cols) LIKE UPPER(N'%0x%')
OR UPPER(@.cols) LIKE UPPER(N'%;%')
OR UPPER(@.cols) LIKE UPPER(N'%''%')
OR UPPER(@.cols) LIKE UPPER(N'%--%')
OR UPPER(@.cols) LIKE UPPER(N'%/*%*/%')
OR UPPER(@.cols) LIKE UPPER(N'%EXEC%')
OR UPPER(@.cols) LIKE UPPER(N'%xp[_]%')
OR UPPER(@.cols) LIKE UPPER(N'%sp[_]%')
OR UPPER(@.cols) LIKE UPPER(N'%SELECT%')
OR UPPER(@.cols) LIKE UPPER(N'%INSERT%')
OR UPPER(@.cols) LIKE UPPER(N'%UPDATE%')
OR UPPER(@.cols) LIKE UPPER(N'%DELETE%')
OR UPPER(@.cols) LIKE UPPER(N'%TRUNCATE%')
OR UPPER(@.cols) LIKE UPPER(N'%CREATE%')
OR UPPER(@.cols) LIKE UPPER(N'%ALTER%')
OR UPPER(@.cols) LIKE UPPER(N'%DROP%')
-- Look for other possible strings used in SQL injection here
BEGIN
SET @.msg = N'Possible SQL injection attempt.';
RAISERROR(@.msg, 16, 1);
RETURN;
END

-- Create the PIVOT query
SET @.sql =
N'SELECT *' + @.newline +
N'FROM' + @.newline +
N' ( SELECT ' + @.newline +
N' ' + QUOTENAME(@.on_rows) + N',' + @.newline +
N' ' + QUOTENAME(@.on_cols) + N' AS pivot_col,' + @.newline +
N' ' + QUOTENAME(@.agg_col) + N' AS agg_col' + @.newline +
N' FROM ' + @.object + @.newline +
N' ) AS PivotInput' + @.newline +
N' PIVOT' + @.newline +
N' ( ' + @.agg_func + N'(agg_col)' + @.newline +
N' FOR pivot_col' + @.newline +
N' IN(' + @.cols + N')' + @.newline +
N' ) AS PivotOutput;';

EXEC sp_executesql @.sql;
GO

Call of the function that flattens the hierarchy, but doesn't populate of of the reporting level columns.

Use AdventureWorks
;

EXEC dbo.usp_pivot
@.schema_name = N'HumanResources',
@.object_name = N'V_EMP_HIER',
@.on_rows = N'EmployeeID',
@.on_cols = N'Level',
@.agg_func = N'MAX',
@.agg_col = N'EmployeeID';
;

Sean, we talked at the Microsoft BI Conference last week in Seattle and you were looking for some help on this posting. I’ve followed up with an internal alias that had some T-SQL gurus on it and hopefully one of the following solutions may help you get going in the right direction. Alternatively, you could consider using Microsoft SQL Server Analysis Services (AS) for this kind of reporting which may make it easier and faster. There is the notion of Parent\Child dimensions built into AS.

Good Luck!

-- Scott

-

<Header clipped>

Perhaps this would help…

set nocount on;

use northwind;

go

-- create helper function fn_nums

-- returning an auxiliary table of numbers

if object_id('dbo.fn_nums', 'if') is not null

drop function dbo.fn_nums;

go

create function dbo.fn_nums(@.max as int)

returns table as return

with

c0 as(select 0 as const union all select 0),

c1 as(select 0 as const from c0 as a, c0 as b),

c2 as(select 0 as const from c1 as a, c1 as b),

c3 as(select 0 as const from c2 as a, c2 as b),

c4 as(select 0 as const from c3 as a, c3 as b),

c5 as(select 0 as const from c4 as a, c4 as b),

c6 as(select 0 as const from c5 as a, c5 as b)

select top(@.max) row_number()

over(order by const) as n

from c6;

go

-- create helper function fn_split

-- splitting a string

if object_id('dbo.fn_split') is not null

drop function dbo.fn_split;

go

create function dbo.fn_split

(@.string varchar(max), @.separator char(1) = ',') returns table

as

return

select

n - len(replace(left(array, n), @.separator, '')) + 1 as pos,

substring(array, n,

charindex(@.separator, array + @.separator, n) - n) as element

from (select @.string as array) as d

join dbo.fn_nums(900)

on n <= len(array)

and substring(@.separator + array, n, 1) = @.separator;

go

-- Solution query

with empscte as

(

select employeeid, reportsto,

'.' + cast(employeeid as varchar(max)) + '.' as thepath

from employees

where reportsto is null

union all

select sub.employeeid, sub.reportsto,

mgr.thepath + cast(sub.employeeid as varchar(max)) + '.'

from empscte as mgr

join employees as sub

on sub.reportsto = mgr.employeeid

)

select *

from (select employeeid, pos, element as managerid

from empscte as e

cross apply dbo.fn_split(stuff(e.thepath, 1, 1, ''), '.') as s) as d

pivot(max(managerid) for pos in([1],[2],[3],[4],[5]/*add more levels here*/)) as p;

-

From: Ty Balascio
Sent: Monday, May 14, 2007 11:09 AM
Subject: RE: T-SQL Question from customer

I was part of a Usenet thread on this many years ago. Here was the preferred solution.

<paste>

-- If a node's parent is 0, then it's the root node

-- Each node has a unique id and a name

CREATE TABLE Tree

(

parent INT NOT NULL DEFAULT 0 CHECK (parent >= 0),

node INT NOT NULL CHECK (node > 0) PRIMARY KEY,

name VARCHAR(20) NOT NULL

)

GO

-- UDF to return all descendants of a given node

-- Node is identified by its id number

-- Distance is the number of links between two nodes

CREATE FUNCTION Descendants(@.root_node INT)

RETURNS @.nodes TABLE

(node INT NOT NULL PRIMARY KEY CHECK (node > 0),

name VARCHAR(20) NOT NULL,

distance INT NOT NULL CHECK (distance >= 0))

AS

BEGIN

IF NOT EXISTS (SELECT * FROM Tree WHERE node = @.root_node)

RETURN

DECLARE @.distance INT,

@.next_distance INT

SELECT @.distance = 0,

@.next_distance = 1

INSERT INTO @.nodes (node, name, distance)

SELECT node, name, @.distance

FROM Tree

WHERE node = @.root_node

WHILE EXISTS (SELECT * FROM @.nodes WHERE distance = @.distance)

BEGIN

INSERT INTO @.nodes (node, name, distance)

SELECT T.node, T.name, @.next_distance

FROM @.nodes AS N

INNER JOIN

Tree AS T

ON N.distance = @.distance AND

N.node = T.parent

SELECT @.distance = @.next_distance,

@.next_distance = @.next_distance + 1

END

RETURN

END

GO

-- Sample tree

INSERT INTO Tree (parent, node, name)

SELECT 0, 1, 'A' -- root node

UNION ALL

SELECT 1, 2, 'B'

UNION ALL

SELECT 1, 3, 'C'

UNION ALL

SELECT 2, 4, 'D'

UNION ALL

SELECT 2, 5, 'E'

UNION ALL

SELECT 3, 6, 'F'

UNION ALL

SELECT 5, 7, 'G'

UNION ALL

SELECT 5, 8, 'H'

UNION ALL

SELECT 5, 9, 'I'

-- All nodes

SELECT *

FROM Descendants(1)

ORDER BY distance, node

-- All nodes from node id 2 (named B)

SELECT *

FROM Descendants(2)

ORDER BY distance, node

</paste>

|||

Below are simpler and more efficient solutions. You don't really need the UDFs or PIVOT clause and other objects. You can do it with a single CTE. The level can be encoded in the hierarchy path so it is just a matter of decoding it the easiest way.

Code Snippet

-- Using Northwind Employees table:

with EmpTree
as
(
select e.EmployeeID, cast(cast(e.EmployeeID as binary(4)) as varbinary(max)) as EmpHier
from Northwind.dbo.Employees as e
where e.ReportsTo is null
union all
select c.EmployeeID, cast(p.EmpHier + cast(c.EmployeeID as binary(4)) as varbinary(max))
from EmpTree as p
join Northwind.dbo.Employees as c
on c.ReportsTo = p.EmployeeID
)
select EmployeeID
, nullif(cast(substring(EmpHier, 1, 4) as int), 0) as lvl_1
, nullif(cast(substring(EmpHier, 5, 4) as int), 0) as lvl_2
, nullif(cast(substring(EmpHier, 9, 4) as int), 0) as lvl_3
, nullif(cast(substring(EmpHier, 13, 4) as int), 0) as lvl_4
, nullif(cast(substring(EmpHier, 17, 4) as int), 0) as lvl_5
, nullif(cast(substring(EmpHier, 21, 4) as int), 0) as lvl_6
, nullif(cast(substring(EmpHier, 25, 4) as int), 0) as lvl_7
, nullif(cast(substring(EmpHier, 29, 4) as int), 0) as lvl_8
, nullif(cast(substring(EmpHier, 33, 4) as int), 0) as lvl_9
, nullif(cast(substring(EmpHier, 37, 4) as int), 0) as lvl_10
from EmpTree;


-- Using AdventureWorks Employee table:

with EmpTree
as
(
select e.EmployeeID, cast(cast(e.EmployeeID as binary(4)) as varbinary(max)) as EmpHier
from AdventureWorks.HumanResources.Employee as e
where e.ManagerID is null
union all
select c.EmployeeID, cast(p.EmpHier + cast(c.EmployeeID as binary(4)) as varbinary(max))
from EmpTree as p
join AdventureWorks.HumanResources.Employee as c
on c.ManagerID = p.EmployeeID
)
select EmployeeID
, nullif(cast(substring(EmpHier, 1, 4) as int), 0) as lvl_1
, nullif(cast(substring(EmpHier, 5, 4) as int), 0) as lvl_2
, nullif(cast(substring(EmpHier, 9, 4) as int), 0) as lvl_3
, nullif(cast(substring(EmpHier, 13, 4) as int), 0) as lvl_4
, nullif(cast(substring(EmpHier, 17, 4) as int), 0) as lvl_5
, nullif(cast(substring(EmpHier, 21, 4) as int), 0) as lvl_6
, nullif(cast(substring(EmpHier, 25, 4) as int), 0) as lvl_7
, nullif(cast(substring(EmpHier, 29, 4) as int), 0) as lvl_8
, nullif(cast(substring(EmpHier, 33, 4) as int), 0) as lvl_9
, nullif(cast(substring(EmpHier, 37, 4) as int), 0) as lvl_10
from EmpTree;

|||

Scott, Ty and Umachandar.

Thank you all for your options. The solutions give us what we need and a few alternatives too.

I really appreciate you time and efforts.


Sean

|||

Two other options that were forwarded to me:

--

Here's another option:

with empscte as
(
select employeeid, managerid, 1 as lvl,
cast(employeeid as varbinary(max)) as binpath
from humanresources.employee
where managerid is null

union all

select sub.employeeid, sub.managerid, mgr.lvl + 1,
mgr.binpath + cast(sub.employeeid as binary(4))
from empscte as mgr
join humanresources.employee as sub
on sub.managerid = mgr.employeeid
)
select replicate(' | ', lvl-1) + cast(employeeid as varchar(10)) as emp,
nullif(0+substring(binpath, 1, 4), 0) as l1,
nullif(0+substring(binpath, 5, 4), 0) as l2,
nullif(0+substring(binpath, 9, 4), 0) as l3,
nullif(0+substring(binpath, 13, 4), 0) as l4,
nullif(0+substring(binpath, 17, 4), 0) as l5,
nullif(0+substring(binpath, 21, 4), 0) as l6,
/* add more levels here if needed */
lvl
from empscte
order by binpath;

Itzik

Another response – this one from Adam.

Maybe I'm missing something--how dynamic do you want this to be? Can you use placeholder columns for levels that may not be there? If so, wouldn't something like the following work fine (you can run it in AW):

with emps as

(

select

e.employeeid,

null as ReportsToLevel1,

null as ReportsToLevel2,

null as ReportsToLevel3,

null as ReportsToLevel4,

null as ReportsToLevel5,

null as ReportsToLevel6,

null as ReportsToLevel7,

null as ReportsToLevel8,

1 as theLevel

from humanresources.employee e

where managerid is null

union all

select

e.employeeid,

case theLevel when 1 then e.managerid else x.ReportsToLevel1 end,

case theLevel when 2 then e.managerid else x.ReportsToLevel2 end,

case theLevel when 3 then e.managerid else x.ReportsToLevel3 end,

case theLevel when 4 then e.managerid else x.ReportsToLevel4 end,

case theLevel when 5 then e.managerid else x.ReportsToLevel5 end,

case theLevel when 6 then e.managerid else x.ReportsToLevel6 end,

case theLevel when 7 then e.managerid else x.ReportsToLevel7 end,

case theLevel when 8 then e.managerid else x.ReportsToLevel8 end,

theLevel + 1 as theLevel

from humanresources.employee e

join emps x on x.employeeid = e.managerid

)

select *

from emps

question with a stored procedure

I have a stored procedure that inserts a new row if the user doesn't exist in the table...that part works. I then need it to check to see if the user has changed their program code and update the row if they have. the way I'm trying to accomplish this is by selecting their id and program code by what I'm passing it, and if it does not exist, I update the row. For some reason it's not updating the table. I'm new to stored procedures so I'm not sure if I'm doing this correctly or not. Can you please take a look and let me know if this looks ok? This is for MSSQL 2000:

CREATE PROCEDURE [dbo].[InsertUpdateProcedure] (@.LastNamevarchar(255),@.FirstNamevarchar(255),@.Emailvarchar(255),@.ColleagueIDvarchar(50),@.Programvarchar(50))AS IFNOT EXISTS(SELECT users_colleague_idFROM ept_usersWHERE users_colleague_id = @.ColleagueID)BEGIN--The row doesn't exist. Insert code goes hereINSERT INTO ept_users (users_colleague_id,users_last_name,users_first_name,users_email_address,users_program)VALUES(@.ColleagueID,@.LastName,@.FirstName,@.Email,@.Program)ENDIFNOT EXISTS(SELECT users_colleague_idFROM ept_usersWHERE users_colleague_id = @.ColleagueIDAND users_program = @.Program)BEGINUPDATE ept_usersSETusers_program = @.Program,users_email_sent = 0,users_billed_current = 0,users_second_email_sent = 0WHEREusers_colleague_id = @.ColleagueIDENDGO
nevermind...it was choking on some null values. All is working now.sql

Question Update statistics

Hi,
1. What is the main difference between update statistics and create
statistics?
2. If I use "update statistics" on a table that does not have any statistics
created, will it create statistics? If yes, what is the difference between
update statistics and create statistics?
3. I take it that if I use update statistics it will only update statistics
that are already exiting.
4. Does update statistics, sp_update stats, sp_createstats and create
statistics create/update statistics on indexes as well?
Thanks,
Jay
"Jay S." <JayS@.discussions.microsoft.com> wrote in message
news:2ECC6B03-31E6-48AF-A5E4-6338179193B0@.microsoft.com...
> Hi,
> 1. What is the main difference between update statistics and create
> statistics?
Update refreshes existing stats. Create makes new ones.

> 2. If I use "update statistics" on a table that does not have any
> statistics
> created, will it create statistics? If yes, what is the difference between
> update statistics and create statistics?
No.

> 3. I take it that if I use update statistics it will only update
> statistics
> that are already exiting.
>
Yes.

> 4. Does update statistics, sp_update stats, sp_createstats and create
> statistics create/update statistics on indexes as well?
sp_updatestats updates stats on an index(only if they are "outdated" in
2005)
> Thanks,
> Jay
Check out this for more info:
http://www.microsoft.com/technet/prodtechnol/sql/2005/qrystats.mspx
Jason Massie
Web: http://statisticsio.com
RSS: http://feeds.feedburner.com/statisticsio

Question Update statistics

Hi,
1. What is the main difference between update statistics and create
statistics?
2. If I use "update statistics" on a table that does not have any statistics
created, will it create statistics? If yes, what is the difference between
update statistics and create statistics?
3. I take it that if I use update statistics it will only update statistics
that are already exiting.
4. Does update statistics, sp_update stats, sp_createstats and create
statistics create/update statistics on indexes as well?
Thanks,
Jay"Jay S." <JayS@.discussions.microsoft.com> wrote in message
news:2ECC6B03-31E6-48AF-A5E4-6338179193B0@.microsoft.com...
> Hi,
> 1. What is the main difference between update statistics and create
> statistics?
Update refreshes existing stats. Create makes new ones.

> 2. If I use "update statistics" on a table that does not have any
> statistics
> created, will it create statistics? If yes, what is the difference between
> update statistics and create statistics?
No.

> 3. I take it that if I use update statistics it will only update
> statistics
> that are already exiting.
>
Yes.

> 4. Does update statistics, sp_update stats, sp_createstats and create
> statistics create/update statistics on indexes as well?
sp_updatestats updates stats on an index(only if they are "outdated" in
2005)
> Thanks,
> Jay
Check out this for more info:
http://www.microsoft.com/technet/pr...5/qrystats.mspx
Jason Massie
Web: http://statisticsio.com
RSS: http://feeds.feedburner.com/statisticsio

Question Update statistics

Hi,
1. What is the main difference between update statistics and create
statistics?
2. If I use "update statistics" on a table that does not have any statistics
created, will it create statistics? If yes, what is the difference between
update statistics and create statistics?
3. I take it that if I use update statistics it will only update statistics
that are already exiting.
4. Does update statistics, sp_update stats, sp_createstats and create
statistics create/update statistics on indexes as well?
Thanks,
Jay"Jay S." <JayS@.discussions.microsoft.com> wrote in message
news:2ECC6B03-31E6-48AF-A5E4-6338179193B0@.microsoft.com...
> Hi,
> 1. What is the main difference between update statistics and create
> statistics?
Update refreshes existing stats. Create makes new ones.
> 2. If I use "update statistics" on a table that does not have any
> statistics
> created, will it create statistics? If yes, what is the difference between
> update statistics and create statistics?
No.
> 3. I take it that if I use update statistics it will only update
> statistics
> that are already exiting.
>
Yes.
> 4. Does update statistics, sp_update stats, sp_createstats and create
> statistics create/update statistics on indexes as well?
sp_updatestats updates stats on an index(only if they are "outdated" in
2005)
> Thanks,
> Jay
Check out this for more info:
http://www.microsoft.com/technet/prodtechnol/sql/2005/qrystats.mspx
--
Jason Massie
Web: http://statisticsio.com
RSS: http://feeds.feedburner.com/statisticsio

Question to index (SQL 2000)

I have got a question concerning multiple indices on one table.
We have an table where two colums combined build a unique index. Does this
index also help to speed up links where only one of the columns is involved,
or does it make senses to define a separate index for that column?
Example:
Fields a and b build an unique index.
Field b is involved in links to other tables.
Index on field b feasible?
TIA,
NorbertNorbert Meiss wrote:
> I have got a question concerning multiple indices on one table.
> We have an table where two colums combined build a unique index. Does this
> index also help to speed up links where only one of the columns is involve
d,
> or does it make senses to define a separate index for that column?
> Example:
> Fields a and b build an unique index.
> Field b is involved in links to other tables.
> Index on field b feasible?
> TIA,
> Norbert
The combined index on a+b will speed up lookups on field a, but not
necessarily on b. I say "not necessarily" because any lookup on b will
perform a scan, but that scan can now be done on the index instead of
the table.
It is certainly feasible to create a second index that uses b+a.
Tracy McKibben
MCDBA
http://www.realsqlguy.com|||"Norbert Meiss" <NorbertMeiss@.discussions.microsoft.com> wrote in message
news:99ACEA45-2216-4B07-B5FF-0C4C82A028A4@.microsoft.com...
> I have got a question concerning multiple indices on one table.
> We have an table where two colums combined build a unique index. Does this
> index also help to speed up links where only one of the columns is
involved,
> or does it make senses to define a separate index for that column?
> Example:
> Fields a and b build an unique index.
> Field b is involved in links to other tables.
> Index on field b feasible?
Yes and no.
If you can do an index on B+A that should cover both B and A.
(though if A has a higher exclusivity than B, A+B and then a separate index
for B MIGHT be better.)

> TIA,
> Norbert

Question to index (SQL 2000)

I have got a question concerning multiple indices on one table.
We have an table where two colums combined build a unique index. Does this
index also help to speed up links where only one of the columns is involved,
or does it make senses to define a separate index for that column?
Example:
Fields a and b build an unique index.
Field b is involved in links to other tables.
Index on field b feasible?
TIA,
NorbertNorbert Meiss wrote:
> I have got a question concerning multiple indices on one table.
> We have an table where two colums combined build a unique index. Does this
> index also help to speed up links where only one of the columns is involved,
> or does it make senses to define a separate index for that column?
> Example:
> Fields a and b build an unique index.
> Field b is involved in links to other tables.
> Index on field b feasible?
> TIA,
> Norbert
The combined index on a+b will speed up lookups on field a, but not
necessarily on b. I say "not necessarily" because any lookup on b will
perform a scan, but that scan can now be done on the index instead of
the table.
It is certainly feasible to create a second index that uses b+a.
Tracy McKibben
MCDBA
http://www.realsqlguy.com|||"Norbert Meiss" <NorbertMeiss@.discussions.microsoft.com> wrote in message
news:99ACEA45-2216-4B07-B5FF-0C4C82A028A4@.microsoft.com...
> I have got a question concerning multiple indices on one table.
> We have an table where two colums combined build a unique index. Does this
> index also help to speed up links where only one of the columns is
involved,
> or does it make senses to define a separate index for that column?
> Example:
> Fields a and b build an unique index.
> Field b is involved in links to other tables.
> Index on field b feasible?
Yes and no.
If you can do an index on B+A that should cover both B and A.
(though if A has a higher exclusivity than B, A+B and then a separate index
for B MIGHT be better.)
> TIA,
> Norbert

Question -sub query

I’m needing help with a query here. I have a table with an ID and Date which are my PK’s.

I believe this will take a sub query. I want several fields pulled (one per ID). It would be the one with the max(date)

Here is what I have so far (yes I know it doesn’t work but you should get the idea).

select myID, myDate, field1, field2, field3, field4

FROM

(select myID,max(myDate)

from myTable1

WHERE

DATALENGTH(field1)> 0OR

DATALENGTH(field2)> 0OR

DATALENGTH(field3)> 0OR

DATALENGTH(field4)> 0

groupby myID)

By the way the sub query here works on it’s own and gives me the records I want, I just need the other fields pulled in there

Here you are:

SELECT t1.myID, t1.myDateMax, t2.field1, t2.field2, t2.field3, t2.field4FROM

(SELECT myID,max(myDate)AS myDateMax

FROM myTable1WHERE field1ISNOTNULLOR field2ISNOTNULLOR field3ISNOTNULLOR field4ISNOTNULL

GROUPBY myID)AS t1INNERJOIN myTable1AS t2ON t1.myID=t2.myIDAND t1.myDateMax=t2.myDate

|||

Beautiful!!

Thank you Limno

sql

Wednesday, March 28, 2012

Question Regarding Views and Indexes

If I have a table defined as follows:
TABLE Customer_Info
Customer_ID Int NOT NULL,
Country nvarchar(225) NOT NULL,
State_Province nvarchar(225) NULL,
Customer_Name nvarchar(225) NULL
The tables primary key and unique index is on Customer_ID
There is also an index on the Country column and a separate index on
the State_Province column.
And then I have a view names USA_Customers ( a standard view, NOT an
indexed view) defines as follows:
SELECT Customer_ID, County, State_Province, Customer_Name
FROM dbo.Customer_Info
WHERE (Country = 'USA')
And I run the following query
Select * from USA_Customers
Where State_Province = 'PA'
Will this query use the index on the State_Province column of the base
table or not when the query is executed? Regardless of the answer, if
there is any documentation that you could point me to that explains
when an index will / will not be used, I would greatly appreciate it.
Please assume there is enough data in the table and enough cardinality
in the indexes that would be desirable to use the indexes.
Thanks
George<GCeaser@.aol.com> wrote in message
news:1151511288.326267.307760@.i40g2000cwc.googlegroups.com...
> If I have a table defined as follows:
> TABLE Customer_Info
> Customer_ID Int NOT NULL,
> Country nvarchar(225) NOT NULL,
> State_Province nvarchar(225) NULL,
> Customer_Name nvarchar(225) NULL
> The tables primary key and unique index is on Customer_ID
> There is also an index on the Country column and a separate index on
> the State_Province column.
> And then I have a view names USA_Customers ( a standard view, NOT an
> indexed view) defines as follows:
> SELECT Customer_ID, County, State_Province, Customer_Name
> FROM dbo.Customer_Info
> WHERE (Country = 'USA')
>
> And I run the following query
> Select * from USA_Customers
> Where State_Province = 'PA'
> Will this query use the index on the State_Province column of the base
> table or not when the query is executed? Regardless of the answer, if
> there is any documentation that you could point me to that explains
> when an index will / will not be used, I would greatly appreciate it.
> Please assume there is enough data in the table and enough cardinality
> in the indexes that would be desirable to use the indexes.
>
The important thing to know here is that views are expanded into the query
plan before optimization. So this query should behave exactly like
SELECT Customer_ID, County, State_Province, Customer_Name
FROM dbo.Customer_Info
WHERE Country = 'USA'
AND State_Province = 'PA'
SQL Server will consider usiing either, both or neither index, and then
should either use State index + Lookups, the Country Index + Lookups, Index
intersection between the two + Lookups, or do a table scan.
David|||<GCeaser@.aol.com> wrote in message
news:1151511288.326267.307760@.i40g2000cwc.googlegroups.com...
> If I have a table defined as follows:
> TABLE Customer_Info
> Customer_ID Int NOT NULL,
> Country nvarchar(225) NOT NULL,
> State_Province nvarchar(225) NULL,
> Customer_Name nvarchar(225) NULL
> The tables primary key and unique index is on Customer_ID
> There is also an index on the Country column and a separate index on
> the State_Province column.
> And then I have a view names USA_Customers ( a standard view, NOT an
> indexed view) defines as follows:
> SELECT Customer_ID, County, State_Province, Customer_Name
> FROM dbo.Customer_Info
> WHERE (Country = 'USA')
>
> And I run the following query
> Select * from USA_Customers
> Where State_Province = 'PA'
> Will this query use the index on the State_Province column of the base
> table or not when the query is executed? Regardless of the answer, if
> there is any documentation that you could point me to that explains
> when an index will / will not be used, I would greatly appreciate it.
> Please assume there is enough data in the table and enough cardinality
> in the indexes that would be desirable to use the indexes.
>
The important thing to know here is that views are expanded into the query
plan before optimization. So this query should behave exactly like
SELECT Customer_ID, County, State_Province, Customer_Name
FROM dbo.Customer_Info
WHERE Country = 'USA'
AND State_Province = 'PA'
SQL Server will consider usiing either, both or neither index, and then
should either use State index + Lookups, the Country Index + Lookups, Index
intersection between the two + Lookups, or do a table scan.
David|||GCeaser@.aol.com wrote:
> If I have a table defined as follows:
> TABLE Customer_Info
> Customer_ID Int NOT NULL,
> Country nvarchar(225) NOT NULL,
> State_Province nvarchar(225) NULL,
> Customer_Name nvarchar(225) NULL
> The tables primary key and unique index is on Customer_ID
> There is also an index on the Country column and a separate index on
> the State_Province column.
> And then I have a view names USA_Customers ( a standard view, NOT an
> indexed view) defines as follows:
> SELECT Customer_ID, County, State_Province, Customer_Name
> FROM dbo.Customer_Info
> WHERE (Country = 'USA')
>
> And I run the following query
> Select * from USA_Customers
> Where State_Province = 'PA'
> Will this query use the index on the State_Province column of the base
> table or not when the query is executed? Regardless of the answer, if
> there is any documentation that you could point me to that explains
> when an index will / will not be used, I would greatly appreciate it.
> Please assume there is enough data in the table and enough cardinality
> in the indexes that would be desirable to use the indexes.
> Thanks
> George
>
It's *probably* going to use the index on the Country column,
accompanied by a bookmark lookup to get the other fields. It depends on
several things - how much data is in the table, how the view is being
queried (directly as your example or as part of a join). The best way
to confirm is to look at the execution plan of your query.|||GCeaser@.aol.com wrote:
> If I have a table defined as follows:
> TABLE Customer_Info
> Customer_ID Int NOT NULL,
> Country nvarchar(225) NOT NULL,
> State_Province nvarchar(225) NULL,
> Customer_Name nvarchar(225) NULL
> The tables primary key and unique index is on Customer_ID
> There is also an index on the Country column and a separate index on
> the State_Province column.
> And then I have a view names USA_Customers ( a standard view, NOT an
> indexed view) defines as follows:
> SELECT Customer_ID, County, State_Province, Customer_Name
> FROM dbo.Customer_Info
> WHERE (Country = 'USA')
>
> And I run the following query
> Select * from USA_Customers
> Where State_Province = 'PA'
> Will this query use the index on the State_Province column of the base
> table or not when the query is executed? Regardless of the answer, if
> there is any documentation that you could point me to that explains
> when an index will / will not be used, I would greatly appreciate it.
> Please assume there is enough data in the table and enough cardinality
> in the indexes that would be desirable to use the indexes.
> Thanks
> George
>
It's *probably* going to use the index on the Country column,
accompanied by a bookmark lookup to get the other fields. It depends on
several things - how much data is in the table, how the view is being
queried (directly as your example or as part of a join). The best way
to confirm is to look at the execution plan of your query.

Question Regarding Views and Indexes

If I have a table defined as follows:
TABLE Customer_Info
Customer_ID Int NOT NULL,
Country nvarchar(225) NOT NULL,
State_Province nvarchar(225) NULL,
Customer_Name nvarchar(225) NULL
The tables primary key and unique index is on Customer_ID
There is also an index on the Country column and a separate index on
the State_Province column.
And then I have a view names USA_Customers ( a standard view, NOT an
indexed view) defines as follows:
SELECT Customer_ID, County, State_Province, Customer_Name
FROM dbo.Customer_Info
WHERE (Country = 'USA')
And I run the following query
Select * from USA_Customers
Where State_Province = 'PA'
Will this query use the index on the State_Province column of the base
table or not when the query is executed? Regardless of the answer, if
there is any documentation that you could point me to that explains
when an index will / will not be used, I would greatly appreciate it.
Please assume there is enough data in the table and enough cardinality
in the indexes that would be desirable to use the indexes.
Thanks
George<GCeaser@.aol.com> wrote in message
news:1151511288.326267.307760@.i40g2000cwc.googlegroups.com...
> If I have a table defined as follows:
> TABLE Customer_Info
> Customer_ID Int NOT NULL,
> Country nvarchar(225) NOT NULL,
> State_Province nvarchar(225) NULL,
> Customer_Name nvarchar(225) NULL
> The tables primary key and unique index is on Customer_ID
> There is also an index on the Country column and a separate index on
> the State_Province column.
> And then I have a view names USA_Customers ( a standard view, NOT an
> indexed view) defines as follows:
> SELECT Customer_ID, County, State_Province, Customer_Name
> FROM dbo.Customer_Info
> WHERE (Country = 'USA')
>
> And I run the following query
> Select * from USA_Customers
> Where State_Province = 'PA'
> Will this query use the index on the State_Province column of the base
> table or not when the query is executed? Regardless of the answer, if
> there is any documentation that you could point me to that explains
> when an index will / will not be used, I would greatly appreciate it.
> Please assume there is enough data in the table and enough cardinality
> in the indexes that would be desirable to use the indexes.
>
The important thing to know here is that views are expanded into the query
plan before optimization. So this query should behave exactly like
SELECT Customer_ID, County, State_Province, Customer_Name
FROM dbo.Customer_Info
WHERE Country = 'USA'
AND State_Province = 'PA'
SQL Server will consider usiing either, both or neither index, and then
should either use State index + Lookups, the Country Index + Lookups, Index
intersection between the two + Lookups, or do a table scan.
David|||GCeaser@.aol.com wrote:
> If I have a table defined as follows:
> TABLE Customer_Info
> Customer_ID Int NOT NULL,
> Country nvarchar(225) NOT NULL,
> State_Province nvarchar(225) NULL,
> Customer_Name nvarchar(225) NULL
> The tables primary key and unique index is on Customer_ID
> There is also an index on the Country column and a separate index on
> the State_Province column.
> And then I have a view names USA_Customers ( a standard view, NOT an
> indexed view) defines as follows:
> SELECT Customer_ID, County, State_Province, Customer_Name
> FROM dbo.Customer_Info
> WHERE (Country = 'USA')
>
> And I run the following query
> Select * from USA_Customers
> Where State_Province = 'PA'
> Will this query use the index on the State_Province column of the base
> table or not when the query is executed? Regardless of the answer, if
> there is any documentation that you could point me to that explains
> when an index will / will not be used, I would greatly appreciate it.
> Please assume there is enough data in the table and enough cardinality
> in the indexes that would be desirable to use the indexes.
> Thanks
> George
>
It's *probably* going to use the index on the Country column,
accompanied by a bookmark lookup to get the other fields. It depends on
several things - how much data is in the table, how the view is being
queried (directly as your example or as part of a join). The best way
to confirm is to look at the execution plan of your query.

Question regarding use of a join to the same table

I have a table, BOOK, which uses BU and Asset and BOOK as a combined unique
identifier. A BU/Asset combination can have up to 4 rows, with different
BOOK values (CORP, FED, AMT - all of which are required, and LOCAL which is
situational).
Due to bad data entry, some of the Assets were not given an AMT row. I have
to identify those BU/Asset combinations.
I know I need to do a join back to the BOOK table, but I can't seem to get
the right statement. Here is my SQL:
select A.BUSINESS_UNIT, A.ASSET_ID, A.BOOK
from PS_BOOK A
right outer join PS_BOOK B
on A.BUSINESS_UNIT = B.BUSINESS_UNIT and
A.ASSET_ID = B.ASSET_ID
where B.BOOK <> 'AMT'
order by A.BUSINESS_UNIT, A.ASSET_ID, A.BOOK
This gives me a double lisitng of rows (of course) and I can visually scan
for those missing 'AMT', but that's way too clunky. Where am I shooting
myself in the foot? What is the correct statement to use to get just a list
of the BU/Asset combinations that are missing 'AMT'?
TIA,
jej1216I tried a simpler stetment:
select A.BUSINESS_UNIT, A.ASSET_ID, A.BOOK
from PS_BOOK A
where EXISTS (select 'x'
from PS_BOOK B
where B.BOOK <> 'AMT')
order by A.BUSINESS_UNIT, A.ASSET_ID, A.BOOK
But I still get both the BU/Asset combination that has 'AMT' as well as the
combination that does not have 'AMT'.
- jej1216
"Joe" wrote:
> I have a table, BOOK, which uses BU and Asset and BOOK as a combined unique
> identifier. A BU/Asset combination can have up to 4 rows, with different
> BOOK values (CORP, FED, AMT - all of which are required, and LOCAL which is
> situational).
> Due to bad data entry, some of the Assets were not given an AMT row. I have
> to identify those BU/Asset combinations.
> I know I need to do a join back to the BOOK table, but I can't seem to get
> the right statement. Here is my SQL:
> select A.BUSINESS_UNIT, A.ASSET_ID, A.BOOK
> from PS_BOOK A
> right outer join PS_BOOK B
> on A.BUSINESS_UNIT = B.BUSINESS_UNIT and
> A.ASSET_ID = B.ASSET_ID
> where B.BOOK <> 'AMT'
> order by A.BUSINESS_UNIT, A.ASSET_ID, A.BOOK
> This gives me a double lisitng of rows (of course) and I can visually scan
> for those missing 'AMT', but that's way too clunky. Where am I shooting
> myself in the foot? What is the correct statement to use to get just a list
> of the BU/Asset combinations that are missing 'AMT'?
> TIA,
> jej1216
>|||On Tue, 16 Oct 2007 08:42:02 -0700, Joe wrote:
>I tried a simpler stetment:
>select A.BUSINESS_UNIT, A.ASSET_ID, A.BOOK
>from PS_BOOK A
>where EXISTS (select 'x'
> from PS_BOOK B
> where B.BOOK <> 'AMT')
>order by A.BUSINESS_UNIT, A.ASSET_ID, A.BOOK
>But I still get both the BU/Asset combination that has 'AMT' as well as the
>combination that does not have 'AMT'.
Hi Joe,
I think you want this one:
SELECT a.BusinessUnit, a.AssetID, a.Book
FROM PS_Book AS a
WHERE NOT EXISTS
(SELECT *
FROM PS_Book AS b
WHERE b.BusienssUnit = a.BusinessUnit
AND b.AssetID = a.AssetID
AND b.Book <> 'AMT');
If that is not it, then see www.aspfaq.com/5006 to find the information
you need to post in order to make it possible for us to help you.
--
Hugo Kornelis, SQL Server MVP
My SQL Server blog: http://sqlblog.com/blogs/hugo_kornelis

Question regarding state of processes in sysprocesses table

hi all,
I am having one question releated to processes in sysprocesses table.
What i want to ask is, is it possible that state of sleeping process
can go change to running state.
If yes, then say suppose i am running one time consuming stored
procedure. Then is it possible that once i start execution of this sp
it sill randomly goto running then sleeping or in idle state.
One more question, when the state of any process goes to sleeping, is
it like after execution of process completed running process goes to
sleeping.
And Is it possible that running process goes to idle state.
Because after executing stored procedure and checking sysprocess table
sometime i am getting entry for sp in sysprocess and some times not.
Please help me if i am wrong.
Thanks in advance.Archana (trialproduct2004@.yahoo.com) writes:
> I am having one question releated to processes in sysprocesses table.
> What i want to ask is, is it possible that state of sleeping process
> can go change to running state.
> If yes, then say suppose i am running one time consuming stored
> procedure. Then is it possible that once i start execution of this sp
> it sill randomly goto running then sleeping or in idle state.
> One more question, when the state of any process goes to sleeping, is
> it like after execution of process completed running process goes to
> sleeping.
> And Is it possible that running process goes to idle state.
>
I have a feeling that your problem is not the one you are asking about.
Normally, a "sleeping" process is a connection that is idle and running
any query. But I have seen "sleeping" also for processes that undeniably
are busy doing something. I have not investigated this in detail, but one
thing to watch out for is the ecid column. A spid can spawn several threads,
when parallelism is employed. And in such case, some threads can be sleeping
while waiting for others to complete, I guess.

> Because after executing stored procedure and checking sysprocess table
> sometime i am getting entry for sp in sysprocess and some times not.
Not sure what you mean here, since you are never able to see a stored
procedure as such in sysprocesses. You can of course see the process that
runs it, but if it disconnects after running the procedure, you may not
see it. (Here it's depends on whether connection pooling is in play.)
Erland Sommarskog, SQL Server MVP, esquel@.sommarskog.se
Books Online for SQL Server 2005 at
http://www.microsoft.com/technet/pr...oads/books.mspx
Books Online for SQL Server 2000 at
http://www.microsoft.com/sql/prodin...ions/books.mspx|||Hi,
Thanks for ur reply.
Ya you are right that we never able to see stored procedure in
sysprocesees.
But See i am running only 4 sp. and then i am getting id of that
process and passing that id to dbcc inputbuffer to get information
about stored procedure along with its parameter.
So i can get total number of stored procedure currently running by
looking at process id.
My question is even after executing long running SP, sometime its entry
is displayed in sysprocess table and sometimes not.
Can u tell me why this is happening.
Any help will be truely appreciated.
Thaks in advance.|||Archana (trialproduct2004@.yahoo.com) writes:
> Ya you are right that we never able to see stored procedure in
> sysprocesees.
> But See i am running only 4 sp. and then i am getting id of that
> process and passing that id to dbcc inputbuffer to get information
> about stored procedure along with its parameter.
> So i can get total number of stored procedure currently running by
> looking at process id.
> My question is even after executing long running SP, sometime its entry
> is displayed in sysprocess table and sometimes not.
> Can u tell me why this is happening.
No, because I don't know how you run the procedures. Do you run them
from an application? In such case, what kind of application? How does
the code look like?
Or do you run them from Query Analyzer or Management Studio?
Best would be if you post a script that demonstrates the problem.
--
Erland Sommarskog, SQL Server MVP, esquel@.sommarskog.se
Books Online for SQL Server 2005 at
http://www.microsoft.com/technet/pr...oads/books.mspx
Books Online for SQL Server 2000 at
http://www.microsoft.com/sql/prodin...ions/books.mspx|||hi,
thanks for your reply.
see suppose i have one stored procedure sp_SetId which is accepting one
int parameter say jobid,
So suppose through one application written in c#.net i am executing
this sp using sqlcommand.commandtext like exec sp_setid 1,
and otehr through sql query analysz.
When i see sysprocess table i get two ides with state as runable for
this stored procedure.
say suppose i am getting processid 65 and 66 for these sp. then to get
exactly which jobid is associated with processid i am calling dbcc
inputbuffer ( 65) where i am getting eventinfo from whihc i can easily
get jobid.
This is all what i am doing.
Most of the time this result is proper.
But sometime even if my sp is running its entry is not getting
displayed in sysprocess table i don't know whether that procedure has
started its execution or not.
Can you tell me what am i doing wrong?
Thanks|||Archana (trialproduct2004@.yahoo.com) writes:
> see suppose i have one stored procedure sp_SetId which is accepting one
> int parameter say jobid,
> So suppose through one application written in c#.net i am executing
> this sp using sqlcommand.commandtext like exec sp_setid 1,
> and otehr through sql query analysz.
> When i see sysprocess table i get two ides with state as runable for
> this stored procedure.
> say suppose i am getting processid 65 and 66 for these sp. then to get
> exactly which jobid is associated with processid i am calling dbcc
> inputbuffer ( 65) where i am getting eventinfo from whihc i can easily
> get jobid.
> This is all what i am doing.
> Most of the time this result is proper.
> But sometime even if my sp is running its entry is not getting
> displayed in sysprocess table i don't know whether that procedure has
> started its execution or not.
If the spid is not present in sysprocesses, that spid is obviously
not running the stored procedure. Or any other stored procedure for
that matter. I would be inclined to assume that you are mistaken about
the spid for your procedure.
If all you want do to is to associate spid with jobid, I suggest that
you add a table:
CREATE TABLE spidjobids
(spid int NOT NULL,
CONSTRAINT default_spid DEFAULT @.@.spid,
started datetime NOT NULL.
CONSTRAINT default_spidjobs_started DEFAULT getdate(),
jobid int NOT NULL,
CONSTRAINT pk_spidjobs PRIMARY KEY (spid, started),
CONSTRAINT u_spidjobs UNIQUE (jobid, started)
)
And then modify the procedure to read from that table.
If this not feasible, maybe my procedure aba_lockinfo can be useful.
This procedure gives you the process information and DBCC INPUTBUFFER in
one go. You find it at http://www.sommarskog.se/sqlutil/aba_lockinfo.html.
Erland Sommarskog, SQL Server MVP, esquel@.sommarskog.se
Books Online for SQL Server 2005 at
http://www.microsoft.com/technet/pr...oads/books.mspx
Books Online for SQL Server 2000 at
http://www.microsoft.com/sql/prodin...ions/books.mspx

Question regarding size of varchar field

Hi,
I am using MSDE together with Enterprise Manager.
I have a table with a field nameddescription.
This field will be filled by a web forms's textbox web control.
The textbox'smaxsize attribute is set to "3000" characters.
What size do I have to adjust for my DB fielddescription?
Is the size of3000 in Enterpise Manager equal to3000 characters for the textbox?
I am just trying to avoid errors if MSDE cuts off the string that comes from the textbox webcontrol.Yes, you should set the width of your varchar column to 3000. This unit of measurement is actually bytes, but each character takes 1byte to store, so in effect the column can hold 3000 characters..
|||

I'm answering a question you didn't ask, but maxsize doesn't work if your textbox is multi-line. I just assumed it would be if you allowed that much in it. If you want to limit a multi-line textbox, you need to use a regular expression validator to do it.

|||Thanks for letting me know - and you are right... the texbox is indeed multi-line.
Maybe you can answer my question I have asked in another thread addressing a regular expression issue I am currently faced with - I am still waiting for some helpers there ...
This is the thread:
http://forums.asp.net/937464/ShowPost.aspx|||One more point is if you will use unicode (nvarchar or nchar data type), then physical size for a character will be doubled which means 2 bytes for a character.
If you run
sp_help TableName
you will see "Length" column which keeps physical length of column in bytes

Monday, March 26, 2012

question please

please i hav a question..can uoy answer me?

i have a workers table which contains 4 records such as (id,name,category, status) ...

category like : a,b,c

for example :

id - name - category - status
1 - Jone - A - free
2 - Tom - B - busy
3 - Adm - c - free
4 - Raul - B - free
5 - Sami -A - busy

i want to write query to obtain 3 workers that their status = free and belong to each category (a,b and c )

such as here :
1 - Jone - A - free
3 - Adm - c - free
4 - Raul - B - free

can you help me ?Hope this work for you.
Good luck!

SELECT id,
name,
category
FROM WORKERS
WHERE status = 'free'

|||

Use this query...

select Workers.* From Workers Join
(
Select Category,Max(main.id) id From Workers main Where 3 =
(Select Count(*) From Workers Sub Where Main.id <= Sub.ID And Main.Category = Sub.Category And Main.Status=Sub.Status) And Status='Free'
Group BY
Category
Union All
Select Category,Max(main.id) From Workers main Where 2 =
(Select Count(*) From Workers Sub Where Main.id <= Sub.ID And Main.Category = Sub.Category And Main.Status=Sub.Status) And Status='Free'
Group BY
Category
Union All
Select Category,Max(main.id) From Workers main Where 1 =
(Select Count(*) From Workers Sub Where Main.id <= Sub.ID And Main.Category = Sub.Category And Main.Status=Sub.Status) And Status='Free'
Group BY
Category
) as Data On Data.id = Workers.Id
Order By 3

It will exactly obtain 3 workers that their status = free and belong to each category

|||

-- --
-- Kanjo:
--
-- The things that I understand from your request are:
-- 1. You do want to filter out any status other
-- than the 'free' status.
-- 2. You want to select the worker information
-- for 'free' workers -- especially the category
-- of the worker.
--
-- The things that I am not sure of are:
-- 1. Do you want to filter out any worker that is
-- not in catories 'A', 'B' or 'C'?
-- 2. Do you want all free users in any of the
-- categories or
-- 3. Do you only want the 'Top' free worker of
-- each of the categories?
-- 4. Are you running SQL Server 2000 or 2005?
-- (In this case it might not matter.)
--
-- Each of these isues has an impact on the way that
-- the query needs to be written.
-- --
set nocount on
declare @.workers table
( id integer not null,
name varchar (20) not null,
category char (1) not null,
status varchar (10) not null
)

insert into @.workers values (1, 'Jone', 'A', 'free')
insert into @.workers values (2, 'Tom' , 'B', 'busy')
insert into @.workers values (3, 'Adm', 'C', 'free')
insert into @.workers values (4, 'Raul', 'B', 'free')
insert into @.workers values (5, 'Sami', 'A', 'busy')
insert into @.workers values (6, 'Roni', 'A', 'free')
insert into @.workers values (7, 'Suzy', 'D', 'free')

--select * from @.workers

-- --
-- If there is no need to filter based on category
-- Vincent's query will work just fine:
-- --
select id,
name,
category
from @.workers
where status = 'free'
-- and category in ('A','B','C')

-- Sample Output:

-- id name category
-- -- -- --
-- 1 Jone A
-- 3 Adm C
-- 4 Raul B
-- 6 Roni A
-- 7 Suzy D

-- --
-- However, if you do need to filter based on the
-- category then the where clause will need to be
-- modified to reflect that need
-- --
select id,
name,
category,
status
from @.workers
where status = 'free'
and category in ('A','B','C')

-- - Sample Output --

-- id name category status
-- -- -- -- -
-- 1 Jone A free
-- 3 Adm C free
-- 4 Raul B free
-- 6 Roni A free


-- --
-- There are other ways of obtaing the "top" list if
-- that is the requirement; this is just one of the
-- ways.
-- --
select a.id,
a.name,
a.category,
a.status
from @.workers a
inner join
( select category,
min (id) as min_id
from @.workers
where category in ('A','B','C')
group by category
) b
on a.id = b.min_id


-- -- Sample Output:

-- id name category status
-- -- -- -- -
-- 1 Jone A free
-- 2 Tom B busy
-- 3 Adm C free

-- --
-- Mani:
--
-- HELP! I am not getting the expected results and
-- I am still trying to figure out why. Can you spot
-- where I went wrong?
-- --
select workers.* From @.workers workers Join
(
Select Category,Max(main.id) id From @.workers main Where 3 =
(Select Count(*) From @.workers Sub Where Main.id < Sub.ID And Main.Category = Sub.Category And Main.Status=Sub.Status) And Status='Free'
Group BY
Category
Union All
Select Category,Max(main.id) From @.workers main Where 2 =
(Select Count(*) From @.workers Sub Where Main.id < Sub.ID And Main.Category = Sub.Category And Main.Status=Sub.Status) And Status='Free'
Group BY
Category
Union All
Select Category,Max(main.id) From @.workers main Where 1 =
(Select Count(*) From @.workers Sub Where Main.id < Sub.ID And Main.Category = Sub.Category And Main.Status=Sub.Status) And Status='Free'
Group BY
Category
) as Data On Data.id = workers.Id
Order By 3


-- Unexpected Output: -

-- id name category status
-- -- -- -- -
-- 1 Jone A free

|||

Fixed... ThanQ!

select workers.* From @.workers workers Join
(

Select Category,Max(main.id) id From @.workers main Where 3 =
(Select Count(*) From @.workers Sub Where Main.id <= Sub.ID And Main.Category = Sub.Category And Main.Status=Sub.Status) And main.Status='Free'
Group BY
Category
Union All
Select Category,Max(main.id) From @.workers main Where 2 =
(Select Count(*) From @.workers Sub Where Main.id <= Sub.ID And Main.Category = Sub.Category And Main.Status=Sub.Status) And main.Status='Free'
Group BY
Category
Union All
Select Category,Max(main.id) From @.workers main Where 1 =
(Select Count(*) From @.workers Sub Where Main.id <= Sub.ID And Main.Category = Sub.Category And Main.Status=Sub.Status) And main.Status='Free'
Group BY
Category
) as Data On Data.id = workers.Id
Order By 3