SQL join to an alias column name in SQL Server - sql-server

Not sure if this is possible but I'm trying to join to an alias column in SQL Server.
Is it possible to change the JOIN below?
JOIN
#LOGFILE ON #CSIQUESTIONLOG.LogSeqNo = #LOGFILE.Seq
AND #LOGFILE.Contcode = 'WCM'
to
JOIN
#LOGFILE ON #CSIQUESTIONLOG.LogSeqNo = #LOGFILE.[SEQ2]
AND #LOGFILE.Contcode = 'WCM'
So it joins to the SEQ2 column - not the SEQ column, and so I only have to run one query
Sample data below:
IF OBJECT_ID('tempdb..#CSIQUESTIONLOG') IS NOT NULL
DROP TABLE #CSIQUESTIONLOG
SELECT *
INTO #CSIQUESTIONLOG
FROM (VALUES ('BA', '2017-01-01','123451', '185', 2),
('BA', '2017-01-01','123452', '185', 4),
('BA', '2017-01-01','123453', '184', 1),
('BA', '2017-01-01','123454', '183', 3),
('BA', '2017-01-01','123455', '182', 5),
('BA', '2017-01-01','123456', '181', 0),
('BA', '2017-01-01','123457', '182', 1),
('BA', '2017-01-01','7684417', '180', 2)) d (Dealer, Created, Logseqno, CSIseqno, Answer)
IF OBJECT_ID('tempdb..#LOGFILE') IS NOT NULL
DROP TABLE #LOGFILE
SELECT *
INTO #LOGFILE
FROM (VALUES (7684417, 'BA', 498, 'WCM', 1261723),
(7669984, 'BA', 38, 'CSI', 1261723),
(7685141, 'BA', 400, 'WCM', 1261750),
(7686369, 'BA', 193, 'CSI', 1261750),
(7692571, 'BA', 401, 'WCM', 1262289),
(7700336, 'BA', 38, 'CSI', 1262289)) d (Seq, Dealer, OpNum, Contcode, ContSeqNo)
SELECT
a.*, x.Seq AS [SEQ2]
FROM
#LOGFILE a
OUTER APPLY
(SELECT Seq
FROM #LOGFILE b
WHERE b.ContSeqNo = a.ContSeqNo AND b.ContCode = 'CSI') x
Final query:
SELECT
#CSIQUESTIONLOG.Created, #CSIQUESTIONLOG.CSIseqno,
#LOGFILE.OpNum,
COUNT (*) AS TOTAL
FROM
#CSIQUESTIONLOG
JOIN
#LOGFILE ON #CSIQUESTIONLOG.LogSeqNo = #LOGFILE.Seq
AND #LOGFILE.Contcode = 'WCM'
GROUP BY
#CSIQUESTIONLOG.Created, #CSIQUESTIONLOG.CSIseqno, #LOGFILE.OpNum

Firstly, in your final query there ins no column Seq2. Those are two seperate queries, and thus, they can't interact with each other.
Without the expected result set, I've just chanegd the SQL to what I believe you're after. If it's not, post your expected result set.
SELECT QL.Created,
QL.CSIseqno,
LF2.OpNum, --Not sure if this should be LF1, or LF2. Guessed 2
COUNT (*) AS TOTAL
FROM #CSIQUESTIONLOG QL
JOIN #LOGFILE LF1 ON QL.LogSeqNo = LF1.Seq AND LF1.Contcode = 'WCM'
JOIN #LOGFILE LF2 ON LF1.ContSeqNo = LF2.ContSeqNo AND LF2.ContCode = 'CSI'
GROUP BY QL.Created, --You were completely missing your GROUP BY
QL.CSIseqno,
LF2.OpNum;

Related

T-SQL- Recursive query- employee hierarchy

I want to use recursive query (it can be cte or anything) where I am trying to pull the executive report - where I input one employee name and I want all the hierarchy related to that employees starting with the top level emloyee (starting with CEO) and then going down.
For example:
If I input the employee name Celia, the report should look like:
CEO
Employees reporting to CEO , let's say MgrX
Employees reporting to MgrX- let's say MgrY
Employees reporting to MgrY - let's say MgrZ
All the Employees reporting to MgrZ including Celia (input parameter).
The query I am trying to use :
with cte1 as
(
select
pa.PERSNBR
,pa.AUTHCD
,pu.VALUE
,hr.File#
,hr.[Payroll Name]
,hr.[Reports To File#]
,hr.[Reports To Name]
,hr.[EMC #]
,hr.[EMC Name]
from
[DNA_Staging].[dbo].[PERSAUTH] pa
join [DNA_Staging].[dbo].[PERSEMPL] pe
on pa.PERSNBR = pe.PERSNBR
join [DNA_Staging].[dbo].[PERSUSERFIELD] pu
on pe.PERSNBR = pu.PERSNBR
and pu.USERFIELDCD = 'EFNR'
and GETDATE() < isnull(pe.inactivedate,getdate()+1)
join [HR_Staging].[dbo].[HR_EmployeeHierarchyStaging] hr
on pu.VALUE = substring(hr.File#,2,6)
or pu.VALUE = substring(hr.File#,3,6)
),
-- find all the data for input payroll name in the parameter
cte2 as (select *
FROM cte1 where [Payroll Name] = 'Acain, Celia T'),
A basic example for your question (you haven't provide any data samples or output examples, so...):
DECLARE #name nvarchar(20) = 'Darkwater'
;WITH emplevels AS (
SELECT *
FROM (VALUES
(1, 'CEO'),
(2, 'MgrX'),
(3, 'MgrY'),
(4, 'MgrZ')
) as t(eid, who)
),
people AS ( --people and there levels
SELECT *
FROM (VALUES
(1, 'Smith', 1),
(2, 'Wake', 2),
(3, 'Cartman', 3),
(4, 'Sanders', 4),
(5, 'MacCormic', 1),
(6, 'Malkovich', 2),
(7, 'Whatever', 2),
(8, 'Darkwater', 3),
(9, 'Leto', 4)
) as t(pid, name, eid)
),
dep AS ( --dependences of levels
SELECT *
FROM (VALUES
(1,1), --CEO - CEO
(1,2), --CEO - MgrX
(2,3), --MgrX - MgrY
(3,4) --MgrY - MgrZ
)as t(eid1,eid2)
),
hier as ( -- get the hierarchy
SELECT d.eid1,
d.eid2
FROM dep d
LEFT JOIN people p ON d.eid2 = p.eid
where name = #name
UNION ALL
SELECT d.eid1,
d.eid2
FROM dep d
INNER JOIN hier h ON d.eid2 = h.eid1
WHERE d.eid2 != d.eid1
)
--here comes heads and who there are
SELECT p.name AS Head,
e.who AS WhoIs
from hier h
LEFT JOIN people p ON p.eid = h.eid1
LEFT JOIN emplevels e ON e.eid = p.eid
ORDER BY e.eid
Result for Darkwater (he is MgrY). We have all MgrX and CEO's:
Head WhoIs
--------- -----
Smith CEO
MacCormic CEO
Wake MgrX
Malkovich MgrX
Whatever MgrX
(5 row(s) affected)

Multiple value IF statement, to show in select

Any help appreciated,
the code below is from a database which someone made, every time a receipt is made a unique receipt id is issued. same when a reversal is made a new receipt is issued. what links the two are the pay in number. If a reverse is issued, the reverse flag changes on the old receipt to Y and the new one says N. i have my query that select Minimum date and Max data, for receipts returned will have a much later date that when it was first created. The issue is when there is no reverse, it still pulls information as the min and max date are the same. I am fully aware that i need an if statement, but have no idea how to do it since i am new to Databases.
Select distinct r.receipt_date, r.receipt_no, r.doc_no as Payin_No,r.trans_amt,l.location_desc, ct.charge_type_desc,
(select un.first_name + ' ' + un.last_name)as cashier,
r.payee, r.comments, r.reverse_flag, ret1.returned_by, ret1.return_date
from Cashier..receipts as r
inner join Cashier..location as l on r.location_id=l.location_id
inner join [Cashier].[dbo].[charge_type] as ct on ct.charge_type_no=r.charge_type_no
inner join Cashier..user_name as un on un.user_name=(UPPER(r.created_by))
inner join (
select receipt_no as Return_Receipt ,
(select un2.first_name + ' ' + un2.last_name) as returned_by,
created_date as return_date, doc_no as Payin_no,
r1.reverse_flag
from Cashier..receipts as r1
inner join Cashier..user_name as un2 on un2.user_name=(UPPER(r1.created_by))
where doc_no = r1.doc_no
and created_date = (select MAX(created_date)
from Cashier..receipts where doc_no = r1.doc_no)) as ret1
on (ret1.Payin_no=r.doc_no)
where r.receipt_date = (select MIN(r1.receipt_date) from Cashier..receipts as r1 where r1.receipt_no = r.receipt_no )
Issue i am having, the return by is the same as created
Desired result
Is this basically what you're trying to do?
-- test data creation, for me
create table receipts (receipt_no int, receipt_date datetime, doc_no int, reverse_flag char(1), returned_by varchar(10), create_date datetime, created_date datetime)
insert into receipts values (1, '1/1/2016', 12345, 'Y', 'John', null, '1/1/2016')
insert into receipts values (2, '2/15/2016', 12345, 'N', null, '2/15/2016', '2/15/2016')
SELECT r.receipt_date, r.receipt_no, r.doc_no, r.reverse_flag, ret1.return_date
FROM receipts r
INNER JOIN (
SELECT doc_no, create_date as return_date
FROM receipts
WHERE reverse_flag = 'N')ret1 on r.doc_no = ret1.doc_no and ret1.return_date > r.receipt_date
WHERE r.reverse_flag = 'Y' and r.doc_no = 12345
If that's your goal, I think you just tack this on to the very end of your query:
and r.receipt_date < ret1.return_date
Edit: Based on your update, I think tack this onto the end:
and convert(date, r.receipt_date) < convert(date, ret1.return_date)
I'm still really not sure what you want.
select *
from ( select doc_no, min(receipt_date) as min_receipt_date
from receipts group by doc_no ) as min_receipt
left outer join ( select doc_no, max(receipt_date) as max_receipt_date
from receipts group by doc_no) as max_receipt
on min_receipt.doc_no = max_receipt.doc_no and
min_receipt.min_receipt_date <> max_receipt.max_receipt_date
for
insert into receipts values (1, '2016-01-01', 12345, 'Y', 'John', null, '2016-01-01');
insert into receipts values (2, '2016-03-15', 12345, 'N', null, '2016-03-15', '2016-03-15');
insert into receipts values (3, '2016-03-15', 123667, 'N', null, '2016-03-15', '2016-03-15');
yields
doc_no min_receipt_date doc_no max_receipt_date
12345 January, 01 2016 00:00:00 12345 March, 15 2016 00:00:00
123667 March, 15 2016 00:00:00 (null) (null)
but it assumes that the return date will never be the same as the original receipt date. I also left off the Y and N flags because I don't see how it's necessary if the min date is always the original purchase date. The other answer here uses the created_date but in your screenshot of the table data, you only show one date so I wrote it assuming only one date (the receipt date). I tested that on MySQL because SQLFiddle was hating on my SQL Server syntax for inserts and I don't have another way to test right now.
This is what i was looking for, figured it out. Thank you Max for opening insights on how i could tackle the problem.
Select distinct r.receipt_date, r.receipt_no, r.doc_no as Payin_No,r.trans_amt,l.location_desc, ct.charge_type_desc,
(select un.first_name + ' ' + un.last_name)as cashier,
r.payee, r.comments, r.cost_centre, r.item, r.programme, r.activity, r.btl_sof, r.reverse_flag, --, ret1.returned_by, ret1.return_date
(case when r.reverse_flag = 'Y' then (select (un2.first_name + ' ' + un2.last_name)from Cashier..receipts as r1
inner join Cashier..user_name as un2 on un2.user_name=(UPPER(r1.created_by)) where created_date = (select MAX(created_date)
from Cashier..receipts where doc_no = r.doc_no)) end ) as returned_by ,
(case when r.reverse_flag = 'Y' then (select created_date from Cashier..receipts as r1
inner join Cashier..user_name as un2 on un2.user_name=(UPPER(r1.created_by)) where created_date = (select MAX(created_date)
from Cashier..receipts where doc_no = r.doc_no)) end ) as returned_date
from Cashier..receipts as r
inner join Cashier..location as l on r.location_id=l.location_id
inner join [Cashier].[dbo].[charge_type] as ct on ct.charge_type_no=r.charge_type_no
inner join Cashier..user_name as un on un.user_name=(UPPER(r.created_by))
where r.receipt_date = (select MIN(r1.receipt_date) from Cashier..receipts as r1 where r1.receipt_no = r.receipt_no )

SQL - add one more column as result of subquery? SQL Server 2008

I have a query which gives me perfectly good results:
select
A.ID_acc, A.ID_us, A.st, table3.KFL,
'100' as myattribute,
'101' as my attribute2
from
SOURCE1 as A
left join
(select
table2.ID_us, table2.ID_acc,
CASE WHEN table2.KFL_type = 'KFL' THEN P.index_num ELSE table2.KFL_type END as KFL
from
(select
table1.ID_us, table1.ID_acc,
CASE WHEN sum(table1.count_kfl) > 1 THEN '9999' WHEN sum(table1.count_kfl) = 1 THEN 'KFL' END as KFL_type
from
(SELECT
ID_us, ID_acc, count(*) as count_kfl
FROM
payments
WHERE
index_num IN (200, 201, 203)
AND (date >= XXXX or date2 >= 'XXXXX')
GROUP BY
1, 2) as table1
group by
1, 2) as table2
join
SOURCE2 as P on table2.ID_us = P.ID_us
and table2.ID_acc = P.ID_acc
where
(P.date>= XXXX or P.date2 >= 'XXXXX')
and index_num in (201,201,203)
group by
1, 2
order by
1, 2) as table3 on table3.ID_us = A.ID_us
and table3.ID_acc = A.ID_acc
where
A.not_deleted >= XXXXXX
This query is not my main question, so I only copied it just to short brief, but I wondering how I can now add one more additional column (result of count operation) as the end of my first query? Just to do not making 2 separately and then mixing results. Naturally I don't want to influence on my earlier fields results.
I have second query which looks like this:
select A.ID_us, count(*)/2 as number
from
SOURCE1 as A
left join
SOURCE3 as B
on A.ID_acc = B.ID_acc
where A.date >= XXXX
group by 1
The link between those 2 queries is attribute ID_acc in SOURCE A which appear in first and in second query.
But don't have idea how do it?
select A.ID_acc, A.ID_us, A.st, table3.KFL, '100' as myattribute, '101' as my attribute2, NEWSOURCE.MYNEW_attribute
from SOURCE1 as A
left join
(
...
)
as table3 on table3.ID_us = A.ID_us and table3.ID_acc = A.ID_acc
where A.not_deleted >= XXXXXX
left join
(
.
.
.
)
as NEWSOURCE
Something like this of course, don't work:///
Have you tried a correlated subquery:
select A.ID_acc, A.ID_us, A.st, table3.KFL, '100' as myattribute,
'101' as my attribute2,
( select count(*)/2 as number from SOURCE1 as IA left join SOURCE3 as IB on
IA.ID_acc = IB.ID_acc and IA.ID_Acc = A.ID_Acc where IA.date >= XXXX ) as NewColumn
from ...
Note the use of new aliases in the correlated subquery.

SQL: Find MIN but greater than a MAX

I am working with task history and trying to find two dates attached to the same record: 1) Most recent time a task was approved (max approve); 2)The first submitted date after said approval.
Here is what I have so far:
Select
a.assn_uid,
max(b.ASSN_TRANS_DATE_ENTERED) as LastApprove,
e.LastSubmitted
FROM [PRJDEV_ProjectWebApp].[pub].[MSP_ASSIGNMENT_TRANSACTIONS] a
inner join [PRJDEV_ProjectWebApp].[pub].[MSP_ASSIGNMENT_TRANSACTIONS_COMMENTS] b
on a.ASSN_TRANS_UID = b.ASSN_TRANS_UID
join (select c.assn_uid,
min(d.ASSN_TRANS_DATE_ENTERED) as LastSubmitted
FROM [PRJDEV_ProjectWebApp].[pub].[MSP_ASSIGNMENT_TRANSACTIONS] c
inner join [PRJDEV_ProjectWebApp].[pub].[MSP_ASSIGNMENT_TRANSACTIONS_COMMENTS] d
on c.ASSN_TRANS_UID = d.ASSN_TRANS_UID
where c.ASSN_UID = '499879BC-28B2-E411-8B0A-00059A3C7A00'
and d.[ASSN_TRANS_COMMENT_TYPE_ENUM] = 0
group by c.assn_uid ) e
on e.ASSN_UID = a.ASSN_UID
where a.ASSN_UID = '499879BC-28B2-E411-8B0A-00059A3C7A00'
and b.[ASSN_TRANS_COMMENT_TYPE_ENUM] = 1
group by a.assn_uid, e.LastSubmitted
This is close, however, it gives me the first time ever that the task was submitted. I am sure that I need to use another subquery, I just dont know how to reference a column within the same result.
Here is the task history. Highlighted are the two dates I am trying to show:
I don't know that I could wade through your query in any reasonable amount of time, but to get the row after a particular row, you'd need to do something like this:
create table #submissions (
ID int,
DateAdded datetime,
SubmissionType nvarchar(100)
)
insert #submissions values
(1, '2010-01-01', 'first ever'),
(1, '2010-01-02', 'second'),
(1, '2010-01-03', 'third'),
(1, '2010-01-04', 'approve'),
(1, '2010-01-05', 'first after approve'),
(1, '2010-01-06', 'second after approve'),
(1, '2010-01-07', 'third after approve')
declare #lastApprovalDate datetime
select #lastApprovalDate = MAX(DateAdded)
from #submissions
where
SubmissionType = 'approve'
declare #firstAfterApprovalDate datetime
select #firstAfterApprovalDate = MIN(DateAdded)
from #submissions
where
DateAdded > #lastApprovalDate
select *
from #submissions
where
DateAdded = #firstAfterApprovalDate
drop table #submissions
In general, get the last approval date using MAX(), then get the first date after that date using MIN() where DateAdded > that max, and then select the row at that date. I added Top 1, just in case there happen to be multiple rows at that time. Not sure if that's possible in your data, but just to be safe.
With some help, we figured out we needed an additional min wrapped around the query.
SELECT
final.assn_uid,
final.LastApprove,
min(final.SubmissionDate) FirstSubmitted
FROM
(Select
a.assn_uid,
max(b.ASSN_TRANS_DATE_ENTERED) as LastApprove,
e.SubmittedDates SubmissionDate
FROM [PRJDEV_ProjectWebApp].[pub].[MSP_ASSIGNMENT_TRANSACTIONS] a
inner join [PRJDEV_ProjectWebApp].[pub].[MSP_ASSIGNMENT_TRANSACTIONS_COMMENTS] b
on a.ASSN_TRANS_UID = b.ASSN_TRANS_UID
join (select c.assn_uid,
(d.ASSN_TRANS_DATE_ENTERED) as SubmittedDates
FROM [PRJDEV_ProjectWebApp].[pub].[MSP_ASSIGNMENT_TRANSACTIONS] c
inner join [PRJDEV_ProjectWebApp].[pub].[MSP_ASSIGNMENT_TRANSACTIONS_COMMENTS] d
on c.ASSN_TRANS_UID = d.ASSN_TRANS_UID
where c.ASSN_UID = '499879BC-28B2-E411-8B0A-00059A3C7A00'
and d.[ASSN_TRANS_COMMENT_TYPE_ENUM] = 0
) e
on e.ASSN_UID = a.ASSN_UID
where a.ASSN_UID = '499879BC-28B2-E411-8B0A-00059A3C7A00'
and b.[ASSN_TRANS_COMMENT_TYPE_ENUM] = 1
and e.SubmittedDates > b.ASSN_TRANS_DATE_ENTERED
group by a.assn_uid, e.SubmittedDates) Final
GROUP BY
final.assn_uid,
final.LastApprove

SQL Server with left join/having sum/group by

Table B holds planned values. Table M hold actual values. I need to find all rows in table B where either there is no actual values (ie. joined) row in table M, or where joined rows have different total actual value rows. I am trying a combination of an outer join and having sum ... group by to achieve this, but it isn't working because the 'orphans' in table B are not being returned.
My query is:-
SELECT B.Id, B.Date, b.Ref,SUM(M.Actual_Volume), SUM(B.Planned_Volume),
SUM(M.Actual_Value),SUM(B.Planned_Value)
FROM
TableB B
left JOIN TableM M on M.Id = B.Id
inner JOIN TableX on TableX.FieldX = B.FieldX
WHERE TableX.FieldY = (SELECT T.FieldY from TableX T where T.FieldX = 408344)
AND TableX.FieldZ = (SELECT T1.FieldZ from TableX T1 where T1.FieldX = 408344)
group by B.Id, B.Date, B.Ref
having SUM(M.Actual_Volume) <> SUM(B.Planned_Volume)
OR SUM(M.Actual_Value) <> SUM(B.Planned_Value)
order by b.Id
If I use = instead of <> to compare the actuals and planned I get rows that join, but I need the rows where the actuals don't equal the planned, or where there is a planned but not an actual.
Thanks!
Table B
Id planned_vol planned val
19 2 350
28 1 100
53 3 650
61 1 50
Table M
M.Id B.Id actual_vol actual_val
58 19 2 350
65 28 1 100
66 53 1 150
So the query should return,
B.Id
53 (because planned_vol <> actual_vol and planned_val <> actual_val)
61 (because B.Id 61 is not in table M)
hth!
This is untested, but I think you need to move the having requirements into the left outer join requirements. Using CTEs (i.e. you need to be using SQL Server 2005 or later for this to work) is one way to do it.
Your having clause is forcing SQL Server to treat the B-M join as an inner join. There may be an alternative approach that does not use CTEs which checks for NULLs in all the right places. But I prefer the divide-and-conquer approach.
WITH
[BAlt] AS
(
SELECT
[B].[Id],
[B].[Date],
[B].[Ref],
SUM([B].[Planned_Volume]) AS [Planned_Volume],
SUM([B].[Planned_Value]) AS [Planned_Value],
FROM [TableB] AS [B]
INNER JOIN [TableX] AS [X1] ON [X1].[FieldX] = [B].[FieldX]
AND [X1].[FieldY] =
(
SELECT
[X2].[FieldY]
FROM [TableX] AS [X2]
WHERE [X2].[FieldX] = 408344
)
AND [X1].[FieldZ] =
(
SELECT
[X3].[FieldZ]
FROM [TableX] AS [X2]
WHERE [X3].[FieldX] = 408344
)
GROUP BY
[B].[Id],
[B].[Date],
[B].[Ref]
),
[MAlt] AS
(
SELECT
[M].[Id],
SUM([M].[Actual_Volume]) AS [Actual_Volume],
SUM([M].[Actual_Value]) AS [Actual_Value]
FROM [M]
GROUP BY
[M].[Id]
)
SELECT
[BAlt].[Id],
[BAlt].[Date],
[BAlt].[Ref],
[BAlt].[Planned_Volume],
[BAlt].[Planned_Value],
[MAlt].[Actual_Volume],
[MAlt].[Actual_Value]
FROM [BAlt]
LEFT OUTER JOIN [MAlt] ON [MAlt].[Id] = [BAlt].[Id]
AND
(
[MAlt].[Actual_Volume] <> [BAlt].[Planned_Volume]
OR [MAlt].[Actual_Value] <> [BAlt].[Planned_Value]
)
ORDER BY
[BAlt].[Id]
I really don't see a problem:
create table b
( B_id int
,PlannedVolume int
,PlannedValue int
)
create table M
( M_id int
,B_id int
,ActualVolume int
,ActualValue int
)
insert b (b_id, PlannedVolume, PlannedValue)
values (19, 2, 350),
(28, 1, 100),
(53, 3, 650),
(61, 1, 50)
insert m (m_id, b_id, ActualVolume, ActualValue)
values (58, 19, 2, 350),
(65, 28, 1, 100),
(66, 53, 1, 150),
(67, 53, 1, 100)
select b.b_id
from b
left join
( select b_id
,sum(ActualVolume) as ActualVolume
,sum(ActualValue) as ActualValue
from m
group by b_id
) m
on m.b_id = b.b_id
where
m.b_id is null
or
(m.ActualValue <> b.PlannedValue and m.ActualVolume <> b.PlannedVolume)

Resources