Set value in column guided by result from select. SQL Server - sql

I have a ready select.
SELECT
[c.MySiteRole].[Id],
[c.MySiteRole].[EmployeeId],
[c.MySiteRole].[RoleId],
[c.MySiteRole].[SiteId],
[e.Site].[Id],
[e.Role].[Id],
[e.Role].[Name],
[e.Role].[RoleTypeId]
FROM
[MySiteRole] AS [c.MySiteRole]
INNER JOIN
[Site] AS [e.Site] ON [c.MySiteRole].[SiteId] = [e.Site].[Id]
INNER JOIN
[Role] AS [e.Role] ON [c.MySiteRole].[RoleId] = [e.Role].[Id]
INNER JOIN
(SELECT TOP(1) [c1].[Id]
FROM [Employee] AS [c1]
WHERE [c1].[UserName] = 'MyUserName'
ORDER BY [c1].[Id]) AS [t0] ON [c.MySiteRole].[EmployeeId] = [t0].[Id]
ORDER BY
[t0].[Id], [e.Role].[Id]
In result of this select I have a list.
Next stage I need to compare the result [e.Role].[Id] from select with few other Id and they must be here, not in other table.
"first-guid-id"
"second-guid-id"
"third-guid-id".
If in result select will be coincidence with one of this id I need set for MyColumn update true. !important - coincidence must be only with guid id from this list. For example if coincidence will be with one of them and in result [e.Role].[Id] will be other guid id - need set false for my update column. It's like "isOnlyProgrammerRoles"
Now I have my update script in this case
UPDATE [dbo].[MyTable]
SET [MyColumn] = CAST (CASE WHEN UserName like '%[^0-9]%' then 0 else 1 end AS BIT)
I need to update my script to something like this
UPDATE [dbo].[MyTable]
SELECT [c.MySiteRole].[Id],
[c.MySiteRole].[EmployeeId],
[c.MySiteRole].[RoleId],
[c.MySiteRole].[SiteId],
[e.Site].[Id],
[e.Role].[Id],
[e.Role].[Name],
[e.Role].[RoleTypeId]
FROM [MySiteRole] AS [c.MySiteRole]
INNER JOIN [Site] AS [e.Site]
ON [c.MySiteRole].[SiteId] = [e.Site].[Id]
INNER JOIN [Role] AS [e.Role]
ON [c.MySiteRole].[RoleId] = [e.Role].[Id]
INNER JOIN (SELECT TOP(1) [c1].[Id]
FROM [Employee] AS [c1]
WHERE [c1].[UserName] = 'MyUserName'
ORDER BY [c1].[Id]) AS [t0]
ON [c.MySiteRole].[EmployeeId] = [t0].[Id]
ORDER BY [t0].[Id],
[e.Role].[Id]
Compare the Result.Id with GUID id from list 'guidId', guidId', guidId'
if one or more coincidence from list(only from list + no more guid id in the result){
SET [MyColumn] = 1 like bit
}

Well, this solution doesn't follow the same table aliasing and it removes the unneeded brackets. I'm not sure what you mean by "no guid in the result...". Anyway, something like this
;with three_guid_count_cte(r_id) as (
SELECT
r.Id
FROM
MySiteRole AS msr on
INNER JOIN Site AS s ON msr.SiteId = s.Id
INNER JOIN Role AS r ON msr.RoleId = r.Id
INNER JOIN (SELECT TOP(1) c1.Id
FROM Employee AS c1
WHERE c1.UserName = 'MyUserName'
ORDER BY c1.Id) AS t0 ON msr.EmployeeId = t0.Id
INNER JOIN (values (guid1), (guid2), (guid3)) t(v) on r.Id=t.v
HAVING
COUNT(*)>1;
UPDATE m
SET [MyColumn] = CAST(1 AS BIT)
FROM
[dbo].[MyTable] m
INNER JOIN three_guid_count_cte tgc on m.????=tgc.r_id;

Related

Multiple Joins less cost way

Below query has 3 tables where I have to do 2 joins to get a column information, It is very slow, is there any effective way to run this query?
SELECT DISTINCT
st.status_c1
FROM
schemaname.tablea st
INNER JOIN (
SELECT
lic.SpecId AS applicationid,
lic.comData AS combusappid,
lic.ageId,
lic.licId,
lic.licid,
lic.appid,
com.nybe_bustbl_id AS busid
FROM
schemaname.tableb lic
INNER JOIN tablec com ON lic.comData = com.comData
WHERE
lic.ageId = '12'
) rt ON
st.ageId = rt.ageId
AND
st.licId = rt.licId
AND
st.licid = rt.licid
AND
st.appid = rt.appid
WHERE
status_id = 3;
Your current query will create extra rows when the JOIN condition is met for multiple entries in either table and then DISTINCT will filter these duplicates out. You could try to cut down the amount of work filtering duplicates by using EXISTS:
SELECT DISTINCT
st.status_c1
FROM schemaname.tablea st
WHERE status_id = 3
AND EXISTS (
SELECT 1
FROM schemaname.tableb lic
WHERE lic.ageId = '12'
AND st.ageId = lic.ageId
AND st.licId = lic.licId
AND st.appid = lic.appid
AND EXISTS(
SELECT 1 FROM tablec com WHERE lic.comData = com.comData
)
);
There is a bunch of redundancy in the query (licid is in the SELECT and ON twice) and you don't need to use subqueries for this. I think this will work:
SELECT DISTINCT st.status_c1
FROM tablea st
INNER JOIN tableb lic ON st.ageId = lic.ageId
AND st.licId = lic.licId
AND st.appid = lic.appid
INNER JOIN tablec com ON lic.comData = com.comData
WHERE status_id = 3
and lic.ageId = '12'
How frequently are you going to run this query, how much time is it taking now and what is the explectation. Are statistcs run on all tha tables.
There are many things which we can think of, but to start with if possible could you plese give ue the like the table structure and explain plan of the query.
Also may be an index on status_c1 table tablea help. As pointed out try removing the join condition which is twice AND st.licid = rt.licid
SELECT DISTINCT st.status_c1
FROM schemaname.tablea st
INNER JOIN (
SELECT
lic.SpecId AS applicationid, lic.comData AS combusappid, lic.ageId, lic.licId, lic.licid,
lic.appid, com.nybe_bustbl_id AS busid
FROM schemaname.tableb lic
INNER JOIN tablec com ON lic.comData = com.comData
WHERE lic.ageId = '12'
) rt ON st.ageId = rt.ageId AND st.licId = rt.licId AND st.licid = rt.licid AND st.appid = rt.appid
WHERE status_id = 3;

How to use keyset pagination?

Suppose I have total 800 eligible rows in database which is ordered by a column requisitionid in descending order. I want to display the records in 80 pages each page having 10 rows. We are using requisitionid as seek predicate. So the predicate should be less than or greater than? As the query will progress from UI (Angular + primeNG), I want to send just one parameter - requisitionid. If it is less than query, then the query will be SELECT ... FROM ... where requisitionid < ?, so here we are talking about first row. If we go for greater than query i.e. SELECT ... FROM ... where requisitionid > ?, here we are talking about last row of the page.
Please refer to Life without offset
EDIT
Actual code:
with topten as (SELECT DISTINCT TOP 10
REQN.CASE_ID
,userContact2.BV_First_Name + ' ' + userContact2.BV_Last_Name ReQCreater
,REQN.BV_Internal_Job_Title
,REQN.BV_Posted_Job_Title as postedJobTitle
,REQN.BV_Status
,REQN.BV_Taleo_Id
,REQN.BV_WD_PositionID
,jobcode.BV_Job_Code
,loc.BV_LocationCode
,loc.BV_LocationName
,D.BV_Division_Code AS 'divCode',
ISNULL(loc.BV_Address1,'') + CASE WHEN ISNULL(loc.BV_Address1,'') = '' THEN '' ELSE ', ' END + ISNULL(loc.BV_Address2,'') + CASE WHEN ISNULL(loc.BV_Address2,'') = '' THEN '' ELSE ', ' END
+ ISNULL(loc.BV_City,'') + CASE WHEN ISNULL(loc.BV_City,'') = '' THEN '' ELSE ', ' END + ISNULL(loc.BV_State,'') + CASE WHEN ISNULL(loc.BV_State,'') = '' THEN '' ELSE (case when ISNULL(loc.BV_ZipCode,'') = '' THEN '' ELSE ', ' END) END
+ ISNULL(loc.BV_ZipCode,'') AS locationAddress
from dbo.CW_V_REQN as REQN
INNER JOIN dbo.CW_TL_Requisition__Location_Master as reqLocLink on REQN.CASE_ID = reqLocLink.FROM_ID
INNER JOIN dbo.CW_V_LOCTMAST as loc on loc.CASE_ID = reqLocLink.TO_ID
INNER JOIN dbo.CW_TL_UserContactInfo__Location_Master as locUserLink on locUserLink.TO_ID = loc.CASE_ID
INNER JOIN dbo.CW_V_USERCONT as userContact on userContact.CASE_ID = locUserLink.FROM_ID
LEFT JOIN dbo.CW_TL_Requisition__Department as reqDeptLink on REQN.CASE_ID = reqDeptLink.FROM_ID
INNER JOIN dbo.CW_V_DEPARTME as dept on dept.CASE_ID = reqDeptLink.TO_ID
LEFT JOIN dbo.CW_TL_UserContactInfo__Department_Master as deptUserLink on dept.CASE_ID=deptUserLink.TO_ID
INNER JOIN dbo.CW_TL_Requisition__Job_Code as reqJobLink on REQN.CASE_ID = reqJobLink.FROM_ID
LEFT JOIN dbo.CW_V_JOBCODE as jobcode on jobcode.CASE_ID = reqJobLink.TO_ID
LEFT JOIN dbo.CW_V_USERCONT as userContact2 on (userContact2.BV_Login_Name = REQN.CREATED_BY)
LEFT JOIN CW_TL_LocationMaster__Division_Master LD ON (LD.FROM_ID = loc.CASE_ID)
LEFT JOIN CW_V_DIVISION D ON (D.CASE_ID = LD.TO_ID)
WHERE userContact.BV_Login_Name = #LOGINNAME
AND REQN.CASE_ID < #MINCASEIDPREVPAGE
ORDER BY REQN.CASE_ID DESC
)
select topten.*
, T.*
from topten
cross join (select min(case_id) as min from topten) as T
For key based pagination on a descending key, the WHERE clause predicate should be < for the next page and > for the previous page. Also, the ORDER BY clause for the previous page needs to be ASC (for the TOP predicate) along an outer DESC (for the descending key display sequence). Below is an example.
--create test table with sample data
CREATE TABLE dbo.YourTable(
requisitionid int PRIMARY KEY
);
WITH
t10 AS (SELECT n FROM (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) t(n))
,t1000 AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS num FROM t10 AS a CROSS JOIN t10 AS b CROSS JOIN t10 AS c)
INSERT INTO dbo.YourTable WITH(TABLOCKX)
SELECT num
FROM t1000
WHERE num <= 800;
GO
--query for first page (page 1) on descending key (returns 800-791)
SELECT TOP(10) requisitionid
FROM YourTable
ORDER BY requisitionid DESC;
GO
--query for next page (page 2) on descending key (returns 790-781)
DECLARE #LastRequisitionIdOnPage int = 791;
SELECT TOP(10) requisitionid
FROM YourTable
WHERE requisitionid < #LastRequisitionIdOnPage
ORDER BY requisitionid DESC;
GO
--query for previous page (page 1) on descending key (returns 800-791)
DECLARE #FirstRequisitionIdOnPage int = 790;
SELECT requisitionid
FROM (
SELECT TOP(10) requisitionid
FROM YourTable
WHERE requisitionid > #FirstRequisitionIdOnPage
ORDER BY requisitionid ASC
) AS prev_page
ORDER BY requisitionid DESC;;
GO
If I understand your question, you should be able to use the follow clause at the end of your SELECT query:
OFFSET (#Page * 10) ROWS FETCH NEXT 10 ROWS ONLY
If this is not what you are looking for, please post your current query so we can see what you are doing now.

How to ignore duplicate records in CTE Select statement?

I am trying to ignore duplicate records in CTE but I am not able to do that, It seems like a SELECT statement inside CTE does not allow to use ROWNUM() variable numrows to condition in WHERE clause as it is showing Invalid column name 'numrows' error while trying to do so.
SQL Query:
DECLARE #BatchID uniqueidentifier = NEWID();
DECLARE #ClusterID SMALLINT = 1;
DECLARE #BatchSize integer = 20000;
DECLARE #myTableVariable TABLE(EventID BIGINT,HotelID int, BatchStatus varchar(50),BatchID uniqueidentifier);
WITH PendingExtResSvcEventsData_Batch
AS(
SELECT TOP (#BatchSize) t.EventID, t.HotelID, t.BatchStatus, t.BatchID, ROW_NUMBER() OVER (PARTITION BY t.EventID ORDER BY t.EventID) numrows
FROM ExtResSvcPendingMsg t WITH (NOLOCK)
WHERE t.ClusterID = #ClusterID AND numrows = 1 AND NOT EXISTS -- not allowed to use WHERE numrows = 1 here showing *Invalid Column Name*
(select 1 from ExtResSvcPendingMsg t2 where t2.BatchStatus = 'Batched'
and t2.EventID = t.EventID and t2.HotelID = t.HotelID)
)
UPDATE PendingExtResSvcEventsData_Batch
SET BatchStatus='Batched',
BatchID = #BatchID
-- WHERE numrows = 1 (not allowed to use WHERE here because of OUTPUT Clause)
OUTPUT INSERTED.* INTO #myTableVariable
SELECT e.ExtResSvcEventID,e.HotelID,e.ID1,e.ID2,e.ExtResSvcEventType,e.HostID,e.StatusCode,e.ChannelID,e.RequestAtTime,e.ProcessTime,e.DateBegin,e.DateEnd,
e.StatusMsg,em.MsgBodyOut,em.MsgBodyIn,e.ChannelResID
FROM ExtResSvcEvent e WITH (NOLOCK)
INNER JOIN #myTableVariable t ON e.ExtResSvcEventID = t.EventID
INNER JOIN ExtResSvcEventXML em with (nolock) on t.EventID = em.ExtResSvcEventID
ORDER BY e.ExtResSvcEventID
I have also tried to use numrows in final SELECT like INNER JOIN #myTableVariable t ON e.ExtResSvcEventID = t.EventID AND t.numrows = 1 but this gives me a error i.e. The column reference "inserted.numrows" is not allowed because it refers to a base table that is not being modified in this statement.
How do I ignore the duplicate records while using SELECT in CTE?
You can't refer to the numrows column in the WHERE clause of the CTE because that column is not calculated at this point in the plan execution. You need to add a second CTE with a select statement where you can refer to the numrows column:
WITH Base AS (
SELECT TOP (#BatchSize) t.EventID, t.HotelID, t.BatchStatus, t.BatchID, ROW_NUMBER() OVER (PARTITION BY t.EventID ORDER BY t.EventID) numrows
FROM ExtResSvcPendingMsg t WITH (NOLOCK)
WHERE t.ClusterID = #ClusterID
AND NOT EXISTS (select 1 from ExtResSvcPendingMsg t2 where t2.BatchStatus = 'Batched' and t2.EventID = t.EventID and t2.HotelID = t.HotelID)
), PendingExtResSvcEventsData_Batch AS (
SELECT EventID,
HotelID,
BatchStatus,
BatchID
WHERE numrows = 1
)
UPDATE...
I can't vouch for the update statement working as you expect it but the PendingExtResSvcEventsData_Batch should now have one row per EventID.

SQL Server - UNION ALL

I'm new to SQL development and I need to do UNION on two select statements. Below is a sample query. The Join tables & conditions, where criteria, columns names and everything is the same in both the select statements except the the primary tables after the FROM clause. I just wanted to know if there is a way to have a single static select query, instead of repeating the same query twice for the UNION (without going for a dynamic query).
SELECT Sum(ABC.Intakes) As TotalIntakes, Sum(ABC.ClientTarget) as TotalClientTarget
FROM(
SELECT Sum(tt.IntakesReceived) As Intakes, Sum(tt.ClientTarget) As ClientTarget,
tt.ProgramId
FROM
(SELECT Count(DISTINCT ClientID) As IntakesReceived,
DATEDIFF(MONTH, L.AwardStartDate, L.AwardEndDate)*L.MonthlyClientTarget As ClientTarget,
L.AwardId, L.ProgramId
FROM IntakeCoverageLegacy As L
LEFT JOIN UserRoleEntity URE ON URE.EntityId = L.AwardId
LEFT JOIN CDPUserRole UR ON URE.UserRoleId = UR.Id AND UR.CDPUserId = #UserId
WHERE (#Program IS NULL OR L.ProgramId IN (SELECT ProgramID FROM #ProgramIDList)
AND (ufn_IsInternalUser(#UserId) = 1
OR (ufn_IsInternalUser(#UserId) = 0 AND UR.CDPUserId = #UserId ))
GROUP BY L.AwardId, L.ProgramId) As tt
GROUP BY tt.ProgramId, tt.ProgramName
UNION ALL
SELECT Sum(tt.IntakesReceived) As Intakes, Sum(tt.ClientTarget) As ClientTarget,
tt.ProgramId
FROM
(SELECT Count(DISTINCT C.ClientID) As IntakesReceived,
DATEDIFF(MONTH, C.AwardStartDate, C.AwardEndDate)*L.MonthlyClientTarget As ClientTarget,
C.AwardId, C.ProgramId
FROM IntakeCoverageCDP As C
LEFT JOIN UserRoleEntity URE ON URE.EntityId = L.AwardId
LEFT JOIN CDPUserRole UR ON URE.UserRoleId = UR.Id AND UR.CDPUserId = #UserId
WHERE (#Program IS NULL OR C.ProgramId IN (SELECT ProgramID FROM #ProgramIDList)
AND (ufn_IsInternalUser(#UserId) = 1
OR (ufn_IsInternalUser(#UserId) = 0 AND UR.CDPUserId = #UserId ))
GROUP BY C.AwardId, C.ProgramId) As tt
GROUP BY tt.ProgramId, tt.ProgramName
) As ABC
GROUP BY ABC.ProgramId
OK... What I posted earlier was a sample query and I've updated the sample to my actual query to make it more clear. It's just the primary tables that are different. My requirement is that - after doing UNION ALL, I need to sum the aggregate columns in the final result, grouping by ProgramId.
I would probably first use UNION for the Client and LegacyClient tables as a derived table and then perform the JOINs:
SELECT C.AwardId,
C.ProgramName,
COUNT(ClientId) AS Intakes
FROM ( SELECT AwardId,
ProgramName,
Id
FROM Client
WHERE Id = #ClientId
UNION
SELECT AwardId,
ProgramName,
Id
FROM LegacyClient
WHERE Id = #ClientId) C
LEFT JOIN UserRoleEntity URE
ON C.AwardId = URE.EntityId
LEFT JOIN UserRole UR
ON URE.UserRoleId = UR.Id AND UR.CDPUserId = #UserId
WHERE (testFunction(#UserId) = 0
OR (testFunction(#UserId) <> 0 AND UR.CDPUserId = #UserId))
GROUP BY C.AwardId,
C.ProgramName;
SELECT C.AwardId, C.ProgramName, Count(ClientId) as Intakes
FROM
(
SELECT Id, AwardId, ProgramName, ClientId FROM Client UNION ALL
SELECT Id, AwardId, ProgramName, ClientId FROM LegacyClient
) C
LEFT OUTER JOIN UserRoleEntity URE ON C.AwardId = URE.EntityId
LEFT OUTER JOIN UserRole UR ON URE.UserRoleId = UR.Id AND UR.CDPUserId = #UserId
WHERE
C.Id = #ClientId
AND (testFunction(#UserId) = 0 OR UR.CDPUserId = #UserId)
GROUP BY C.AwardId, C.ProgramName
Using testFunction() twice isn't really necessary (unless null is one of the outputs.)
You might also prefer to filter on ClientId outside of the union. I'm guess your purpose in rewriting it to avoid the duplicated logic. You might still want to see which one is better handled by the optimizer.
Also, I used a UNION ALL. I'm thinking you imagine only one result from one of the two tables. As you originally wrote it that count column is going to factor into the union.
Counting on ClientId seems odd. So does having a parameter named #ClientId that doesn't seem to match up with the ClientId column.

Query, subquery and using as variables from subquery

Is it not possible to use the "as [item] and then use the item variable in the query.
For example:
select c.category as [category],c.orderby as [CatOrder], m.masterno, m.master
,-- select OUT (select count(*) from rentalitem ri with (nolock),
rentalitemstatus ris with (nolock),
rentalstatus rs with (nolock)
where ri.rentalitemid = ris.rentalitemid
and ris.rentalstatusid = rs.rentalstatusid
and ri.masterid = m.masterid
and rs.statustype in ('OUT', 'INTRANSIT', 'ONTRUCK')) as [qtyout]
,-- select OWNED owned=
(select top 1 mwq.qty
from masterwhqty mwq
where mwq.masterid = m.masterid)
, -([owned]-[qtyout]) as [Variance]
from master m
inner join category c on c.categoryid=m.categoryid and c.categoryid=#category
inner join inventorydepartment d on c.inventorydepartment=#department
I cannot seem to use qtyout or owned when calculating variance. How can I do that?
You can also use a table variable and then reference that table variable like you are trying to do above....here's an example from MSDN
USE AdventureWorks2012;
GO
DECLARE #MyTableVar table(
EmpID int NOT NULL,
OldVacationHours int,
NewVacationHours int,
ModifiedDate datetime);
UPDATE TOP (10) HumanResources.Employee
SET VacationHours = VacationHours * 1.25,
ModifiedDate = GETDATE()
OUTPUT inserted.BusinessEntityID,
deleted.VacationHours,
inserted.VacationHours,
inserted.ModifiedDate
INTO #MyTableVar;
--Display the result set of the table variable.
SELECT EmpID, OldVacationHours, NewVacationHours, ModifiedDate
FROM #MyTableVar;
GO
--Display the result set of the table.
SELECT TOP (10) BusinessEntityID, VacationHours, ModifiedDate
FROM HumanResources.Employee;
GO
need to move your calculated fields into a subquery, and then use them by their alias in the outer query.
select subquery.*, -([owned]-[qtyout]) as [Variance]
from
(
select c.category as [category],c.orderby as [CatOrder], m.masterno, m.master
,-- select OUT (select count(*) from rentalitem ri with (nolock),
rentalitemstatus ris with (nolock),
rentalstatus rs with (nolock)
where ri.rentalitemid = ris.rentalitemid
and ris.rentalstatusid = rs.rentalstatusid
and ri.masterid = m.masterid
and rs.statustype in ('OUT', 'INTRANSIT', 'ONTRUCK')) as [qtyout]
,-- select OWNED owned=
(select top 1 mwq.qty
from masterwhqty mwq
where mwq.masterid = m.masterid) as [owned]
from master m
inner join category c on c.categoryid=m.categoryid and c.categoryid=#category
inner join inventorydepartment d on c.inventorydepartment=#department
) as subquery
YOu need to use a subquery:
select t.*,
([owned]-[qtyout]) as [Variance]
from (<something like your query here
) t
You query, even without the comments, doesn't quite make sense (select OUT (select . . . for isntance). But, the answer to your question is to define the base variables in a subquery or CTE and then subsequently use them.
And, you are calling the difference "variance". Just so you know, you are redefining the statistical meaning of the term (http://en.wikipedia.org/wiki/Variance), which is based on the squares of the differences.