Access Query; Creating Master/Slave from list - sql

Asked a question a few days ago, but have decided to go down a differnt route so am re-doing the question as the edit's were getting a bit messy.
I have a list of data containing two columns:
pID sKey
100 8611
100 2318
101 3516
101 5413
102 6546
102 5646
102 8411
103 8795
103 5845
The first sKey to appear would become the Master sKey for that pID and each sKey after would be a slave. The data would look like this.
pID sKey sKey_1
100 8611 2318
101 3516 5413
102 6546 5646
102 6546 8411
103 8795 5845
This query gets me close
SELECT MyTable.pID, MyTable.sKey, MyTable_1.sKey
FROM MyTable
INNER JOIN MyTable AS MyTable_1
ON MyTable.pID = MyTable_1.pID
WHERE (((IIf([MyTable.sKey]=[MyTable_1.sKey],"Y","N"))="N"))
pID sKey sKey
100 2318 8611
100 8611 2318
101 3516 5413
101 5413 3516
102 5646 6546
102 5646 8411
102 6546 5646
102 6546 8411
102 8411 5646
102 8411 6546
103 5845 8795
103 8795 5845
But as you can see it reverses the order and doubles each one up, and when it hits an instance where there is 3 or more sKey's it goes a bit crazy :\
Anyone have any ideas, or can point me in the right direction?

If you're trying to use the MIN(skey) as your Master, then something like this should work:
select
p.pId,
p.skey,
p3.skey skey1
from mytable p
join (select pID, min(skey) minskey
from mytable
group by pID
) p2 on p.pid = p2.pid and p.skey = p2.minskey
join mytable p3 on p.pid = p3.pid and p.skey != p3.skey
SQL Fiddle Demo
This produces slightly different results than yours above.
If your desired results are to use the first skey that shows up, then I'd recommend adding an Identity/AutoNumber column to your table just to seed from. You can't guarantee the order of the results without that column. So assuming you were to add such a column, then something like this should work:
select
p.pId,
p.skey,
p3.skey skey1
from mytable p
join (select pID, min(id) minId
from mytable
group by pID
) p2 on p.id = p2.minId
join mytable p3 on p.pid = p3.pid and p.id <> p3.id
order by p.pid, p3.id
SQL Fiddle Demo With AutoNumber

Related

Run a query based on the values returned by another query

Consider the tables:
WorkOrder Date
101 1/2/2020
101 1/2/2020
102 1/2/2020
102 1/3/2020
101 1/3/2020
103 1/4/2020
104 1/4/2020
104 1/5/2020
103 1/5/2020
104 1/5/2020
102 1/5/2020
WorkOrder Operation
101 Process
101 Run
102 Process
102 Run
101 Ship
103 Process
104 Process
104 Run
103 Run
104 Ship
102 Ship
If I were to run query1:
SELECT *
FROM table1
JOIN table2 on table1.WorkOrder = table2.WorkOrder
WHERE Date = '1/4/2020'
I want a query that would return all of the rows for open work orders in that date range (i.e. include the process, run, and ship). This would be the equivalent to what I want returned:
SELECT *
FROM table
JOIN table2 on table1.WorkOrder = table2.WorkOrder
WHERE WorkOrder = '102' AND Work Order = '103' AND Work Order = '104'
Therefore the desired output would be:
102 Process 1/2/2020
102 Run 1/3/2020
103 Process 1/4/2020
104 Process 1/4/2020
104 Run 1/5/2020
103 Ship 1/5/2020
104 Ship 1/5/2020
102 Ship 1/5/2020
But I don't want to specify each of the work orders returned from query1. Also, how could this work with a date range:
SELECT *
FROM table
JOIN table2 on table1.WorkOrder = table2.WorkOrder
WHERE Date <= 'X' AND Date >= 'Y'
If you want all the rows for work orders that:
started on or before that date, and
ended on of after that date, and
include all three operations (process, run, and ship).
You can do:
select *
from t
where workorder in (
select a.workorder
from t a
join t b on b.workorder = a.workorder
join t c on c.workorder = a.workorder
where a.operation = 'Process'
and b.operation = 'Run'
and c.operation = 'Ship'
and a.date <= '2020-01-04'
and c.date >= '2020-01-04'
) x
(if you are on ORACLE database)
You can use WITH clause to define a temporal table
WITH query1 as -- query1 is the name of this temporal table
(
SELECT *
FROM table
WHERE Date = '1/4/2020'
)
SELECT *
FROM query1 -- you can do querys in query1 (the temporal table)
WHERE WorkOrder = '102'
AND Work Order = '103'
AND Work Order = '104'
I am not sure if this is something you are looking for..
I am assuming 'Process' is considered as Open order. Below query is not tested by the way:
Select a.WorkOrder, a.Date, a.Operation yourtable a WHERE a.Operation IN
(Select Operation from yourtable where Date ='1/4/2020') ;

How to join three tables in SQL Server 2012 and calculate ranking based on 2 attributes

I have 3 tables:
tblEmployee
E_ID E_Name E_City
--------------------------------
101 sasa Mumbai
102 sdf California
103 trt Illinois
104 dssd Texas
105 trt Pennsylvania
106 wee Arizona
107 rer Texas
108 wqe California
109 sadd Michigan
tblGen
Tgenerate is boolean value
Emp_ID Tgenerate
--------------------
105 1
108 1
102 1
102 1
102 0
104 1
107 0
108 1
109 0
And the tblStat:
Emp_ID Status
------------------
103 Pending
107 Pending
103 Pending
101 Delivered
104 Pending
104 Pending
108 Pending
101 Delivered
105 Delivered
I have to join these 3 tables and want output like this
E_Name EmployeeID City TgenerateCount Delivered_Count Ranking
TgenerateCount is calculated for every employee. It is count of TgenerateCount having value 1, for ex 102 has 2 TgenerateCount and 109 has 0 TgenerateCount.
Delivered_Count is count of Status of those who has 'Delivered' status. For ex. 101 has 2 Delivered. I want to display every user in the output table.
Any help would be greatly appreciated.
As your two fact tables have a many:1 relationship with your dimension table, you should aggregate them before joining them.
SELECT
e.*,
COALESCE(g.rows, 0) AS TgenerateCount,
COALESCE(s.rows, 0) AS DeliveredCount,
RANK() OVER (ORDER BY COALESCE(g.rows, 0) + COALESCE(s.rows,0) DESC) AS ranking
FROM
tblEmployee e
LEFT JOIN
(
SELECT E_ID, COUNT(*) AS rows FROM tblGen WHERE Tgenerate = 1 GROUP BY E_ID
)
g
ON g.E_ID = e.E_ID
LEFT JOIN
(
SELECT E_ID, COUNT(*) AS rows FROM tblStat WHERE STATUS = 'Delivered' GROUP BY E_ID
)
s
ON s.E_ID = e.E_ID
You've been unclear on how the ranking should be completed, so this simply gives an example ranking.

SQL Query Joining 2 Tables and Getting Required Data

I have 2 Tables:
Merchant having 3 columns MerchantID, MemberID, MerchantName
Member having 3 columns MemberID, ReportID, MemberName
The sample values are:
MerchantID MemberID MerchantName
1101 101 ABC
1102 102 DEF
1103 103 XYZ
MemberID ReportID MemberName
101 112 GHI
101 111 JKL
101 115 MNO
102 111 kjh
102 116 hgf
102 117 oiu
103 118 hgh
103 119 jhf
I need to get the MerchantNames which have Member IDs that are not associated with 111 Report ID.
The query o/p should be: XYZ.
Kindly let me know the most optimized SQL query which can achieve this.
Thanks in advance.
This is a classic usecase for the EXISTS operator:
SELECT MerchantName
FROM Merchant
WHERE NOT EXISTS (SELECT 1
FROM Member
WHERE Member.MemberId = Merchant.MemberId AND
ReportId = 111)
with JOIN:
SELECT mer.MerchantName FROM [Merchant] mer
LEFT JOIN [Member] mem ON mer.MemberId = mem.MemberId
AND mem.ReportId != 111;
Or
SELECT mer.MerchantName FROM [Merchant] mer
LEFT JOIN [Member] mem ON mer.MemberId = mem.MemberId
AND mem.ReportId <> 111;

MSSQL join query with Group by

my table structure like this:
ID SID Type Description SN
82 372 PC XX 1234ZZ
83 372 Monitor YYY 2234ZZ
587 444 PC BBB 2255XX
588 444 Monitor CCC 4512XC
i would like to create a VIEW to show all record in same row group by SID (Staff ID)
my sql as follows:
SELECT DISTINCT a.SID,
CAST(b.Description AS NVARCHAR(100)) AS Name_PC,
CAST(b.SN AS NVARCHAR(100)) AS SN_PC,
CAST(c.Description AS NVARCHAR(100)) AS Name_Monitor,
CAST(c.SN AS NVARCHAR(100)) AS SN_Monitor,
dbo.StaffDB.DisplayName
FROM dbo.IT_Equ AS a INNER JOIN
dbo.StaffDB ON a.SID = dbo.StaffDB.SID LEFT OUTER JOIN
dbo.IT_Equ AS b ON a.SID = b.SID AND b.Type = 'PC' LEFT OUTER JOIN
dbo.IT_Equ AS c ON a.SID = c.SID AND c.Type = 'Monitor'
WHERE (b.Description IS NOT NULL) AND (b.SN IS NOT NULL)
AND (c.Description IS NOT NULL) AND (c.SN IS NOT NULL)
GROUP BY a.SID, CAST(b.Description AS NVARCHAR(100)),
CAST(b.SN AS NVARCHAR(100)),
CAST(c.Description AS NVARCHAR(100)),
CAST(c.SN AS NVARCHAR(100)),
StaffDB.DisplayName
the code works fine if staf only had one record for PC and monitor, it will show the following results:
SID Name_PC SN_PC Name_Monitor SN_Monitor DisplayName
372 XX 1234ZZ YYY 2234ZZ Peter
444 BBB 2255XX CCC 4512XC John
but if the staff had more than one PC record or monitor record, it will create duplicate records such as
original record in db:
ID SID Type Description SN
106 476 PC PC018 84TK5
107 476 Monitor LCD018 60P5D
421 476 PC PC220 85HYC
422 476 Monitor LCD220 51RMR
the result like this:
SID Name_PC SN_PC Name_Monitor SN_Monitor DisplayName
476 PC018 84TK5 LCD018 60P5D Mary
476 PC018 84TK5 LCD220 51RMR Mary
476 PC220 85HYC LCD018 60P5D Mary
476 PC220 85HYC LCD220 51RMR Mary
is it possible to enhance the query to become this ?
SID Name_PC SN_PC Name_Monitor SN_Monitor DisplayName
476 PC018 84TK5 LCD018 60P5D Mary
476 PC220 85HYC LCD220 51RMR Mary
thanks
Problem is in the data - you have to fix duplicates. Obviously 1 monitor belongs to 2 PCs -
PC018 - 60P5D and PC220 - 60P5D.
Alternatively you can try to arrange them and somehow to take 1st SN for the 1st PC and so on, but I don't think this is the right way.
how to you want to determine which sn_pc you want to use?
A distinct will not solve your problem, a distinct only eliminate identical lines.
You have to aggregate if it's possible : min(sn_pc)
You can use view function : row_number over (partition by sid, name_pc order by sn_pc) in a subquery then where rownum = 1
But when reading again the results, it seems you are missing a join criteria when joining your tables
dbo.IT_Equ AS c ON a.SID = c.SID AND c.Type = 'Monitor'
Here is the problem, use a subquery to only select the last line if possible.

SQL Server : take 1 to many record set and make 1 record per id

I need some help. I need to take the data from these 3 tables and create an output that looks like below. The plan_name_x and pending_tallyx columns are derived to make one line per claim id. Each claim id can be associated to up to 3 plans and I want to show each plan and tally amounts in one record. What is the best way to do this?
Thanks for any ideas. :)
Output result set needed:
claim_id ac_name plan_name_1 pending_tally1 plan_name_2 Pending_tally2 plan_name_3 pending_tally3
-------- ------- ----------- -------------- ----------- -------------- ----------- --------------
1234 abc cooks delux_prime 22 prime_express 23 standard_prime 2
2341 zzz bakers delpux_prime 22 standard_prime 2 NULL NULL
3412 azb pasta's prime_express 23 NULL NULL NULL NULL
SQL Server 2005 table to use for the above result set:
company_claims
claim_id ac_name
1234 abc cooks
2341 zzz bakers
3412 azb pasta's
claim_plans
claim_id plan_id plan_name
1234 101 delux_prime
1234 102 Prime_express
1234 103 standard_prime
2341 101 delux_prime
2341 103 standard_prime
3412 102 Prime_express
Pending_amounts
claim_id plan_id Pending_tally
1234 101 22
1234 102 23
1234 103 2
2341 101 22
2341 103 2
3412 102 23
If you know that 3 is always the max amount of plans then some left joins will work fine:
select c.claim_id, c.ac_name,
cp1.plan_name as plan_name_1, pa1.pending_tally as pending_tally1,
cp2.plan_name as plan_name_2, pa2.pending_tally as pending_tally2,
cp3.plan_name as plan_name_3, pa3.pending_tally as pending_tally3,
from company_claims c
left join claim_plans cp1 on c.claim_id = cp1.claim_id and cp1.planid = 101
left join claim_plans cp2 on c.claim_id = cp2.claim_id and cp2.planid = 102
left join claim_plans cp3 on c.claim_id = cp3.claim_id and cp3.planid = 103
left join pending_amounts pa1 on cp1.claim_id = pa1.claimid and cp1.planid = pa1.plainid
left join pending_amounts pa2 on cp2.claim_id = pa2.claimid and cp2.planid = pa2.plainid
left join pending_amounts pa3 on cp3.claim_id = pa3.claimid and cp3.planid = pa3.plainid
I would first join all your data so that you get the relevant columns: claim_id, ac_name, plan_name, pending tally.
Then I would add transform this to get plan name and plan tally on different rows, with a label tying them together.
Then it should be easy to pivot.
I would tie these together with common table expressions.
Here's the query:
with X as (
select cc.*, cp.plan_name, pa.pending_tally,
rank() over (partition by cc.claim_id order by plan_name) as r
from company_claims cc
join claim_plans cp on cp.claim_id = cc.claim_id
join pending_amounts pa on pa.claim_id = cp.claim_id
and pa.plan_id = cp.plan_id
), P as (
select
X.claim_id,
x.ac_name,
x.plan_name as value,
'plan_name_' + cast(r as varchar(max)) as label
from x
union all
select
X.claim_id,
x.ac_name,
cast(x.pending_tally as varchar(max)) as value,
'pending_tally' + cast(r as varchar(max)) as label
from x
)
select claim_id, ac_name, [plan_name_1], [pending_tally1],[plan_name_2], [pending_tally2],[plan_name_3], [pending_tally3]
from (select * from P) p
pivot (
max(value)
for label in ([plan_name_1], [pending_tally1],[plan_name_2], [pending_tally2],[plan_name_3], [pending_tally3])
) as pvt
order by pvt.claim_id, ac_name
Here's a fiddle showing it in action: http://sqlfiddle.com/#!3/68f62/10