I have a table with six columns:
EKey ABC XYZ DOB My_Min Row_Num
---- ---- --- ---- ------ -------
101 AB10 123 1946 100 1
103 AB10 123 1946 200 2
201 TN10 456 1955 150 1
220 TN10 456 1955 240 2
216 TN10 456 1955 80 3
214 TN10 456 1955 80 4
I want to compute a new column Required_Min which should have the values as shown below:
EKey ABC XYZ DOB My_Min Row_Num Required_Min
---- ---- --- ---- ------ ------- ------------
101 AB10 123 1946 100 1 100
103 AB10 123 1946 200 2 100
201 TN10 456 1955 150 1 80
220 TN10 456 1955 240 2 80
216 TN10 456 1955 80 3 80
214 TN10 456 1955 80 4 80
Im using SQL for this, i.e., SSMS. Please help.
You can JOIN the table back to itself using the MIN aggregate:
select t.ekey, t.abc, t.xyz, t.dob, t.my_min, t.rownum,
t2.required_min
from yourtable t
join (
select ekey, min(my_min) required_min
from yourtable
group by ekey
) t2 on t.ekey = t2.ekey
If your uniqueness is based on ABC+XYZ+DOB, you can do the following:
with TableMin as
(select ABC,XYZ,DOB,min(My_min) as My_min
group by ABC,XYZ,DOB
from Table1)
update t1 set t1.Required_Min=tm.My_min
from Table1 t1 inner join TableMin tm on t1.ABC=tm.ABC and t1.XYZ=tm.XYZ and t1.DOB=tm.DOB
But this join is quite hard for server with big amount of data. If ABC+XYZ in unique key (or even ABC), use this instead of full ABC+XYZ+DOB.
This should give you the desired results:
select EKey = t.EKey ,
ABC = t.ABC ,
XYZ = t.XYZ ,
DOB = t.DOB ,
My_Min = t.My_Min ,
Row_Num = t.Row_Num ,
Required_Min = min(t.My_Min) over( partition by t.ABC , t.XYZ , t.DOB )
from dbo.my_table t
order by t.ABC ,
t.XYZ ,
t.DOB ,
t.Row_Num
If you actually want to add a new column to the table, then you'll need to do something like this:
alter table dbo.my_table add column Required_Min int null
go
update dbo.my_table
set Required_Min = s.Required_Min
from dbo.my_Table t
join ( select ABC , XYZ , DOB , Required_Min = min(My_Min)
from dbo.my_table
group by ABC , XYZ , DOB
) s on s.ABC = t.ABC
and s.XYZ = t.XYZ
and x.DOB = t.DOB
go
alter table dbo.my_table alter column Required_Min int not null
go
The update could also be standard SQL, using a correlated subquery instead of a derived table. Assuming decent indexing, the execution plans shouldn't vary too much:
update dbo.my_table
set Required_Min = ( select min(My_Min)
from dbo.my_table x
where x.ABC = dbo.my_table.ABC
and x.XYZ = dbo.my_table.XYZ
and x.DOB = dbo.my_table.DOB
)
I'm assuming ssms implies sql server. I'm assuming that you want the minimum "my_min" from rows with the same "RowNum"
try this:
update table_name as outer
set outer.Required_Min = (select min(My_Min)
from table_name as inner
where inner.RowNum = outer.RowNum)
-edit-
new assumption: ABC+XYZ+DOB form a natural key:
update table_name as outer
set outer.Required_Min = ( select min(My_Min)
from table_name as inner
where inner.ABC = outer.ABC
and inner.XYZ = outer.XYZ
and inner.DOB = outer.DOB )
Looks like a job for analitical func PARTITION BY:
select EKey, ABC, XYZ, DOB, My_Min, Row_Num,
min(My_Min) OVER (PARTITION BY ABC, XYZ, DOB) as Required_Min
from Stats
Also, I recommend you to do not store 'Required_Min' as a column, but compute it on demand in a view or query. Otherwise, you'll have to spend your time on providing data relevance (triggers or smth ). So, I would build specific inedexes instead to improve query perfomance.
Related
Need to find the missing numbers which have been deleted or a Column does not have yet.
For example:
i have a table Named Person have Columns [PersonID] [PersonName]
[PersonID] is primary and incremented Number e.g. From 1 to N.
PersonID PersonName
1001 ABC
1002 ABC
1003 XYZ
1004 MNO
1006 ABC
1008 MNO
1009 ABC
1010 ABC
1011 XYZ
1014 ABC
1015 ABC
1016 XYZ
1017 MNO
In the given table ,there are some missing numbers in Column PersonID like
1005
1007
1012
1013
Need to find the missing Numbers only.
Note: There are more than 20 million records in my table.
So please suggest a faster method to find the desired numbers.
Thanks to all of you who supported and share some points. I have found the way to find the Missing using ROWNUMBER().
SELECT
NOTEXIST FROM (
SELECT ROW_NUMBER() OVER (ORDER BY PERSONID) NOTEXIST ,PERSONID FROM #A ) T
WHERE NOTEXIST NOT IN ( SELECT PERSONID FROM PERSONID )
Create another table and populate all the numbers between Min and Max ranges of PersonID. Do an anti join (Left/right) to get the list of numbers missing.
select * from NewIDTable a
left join OriginalTable b on a.PersonID=b.PersonID
where b.Personid is null
The simplest way is to get ranges. You can do this with lead():
select personid + 1, next_personid - 1 as end_range,
next_personid - personid - 1 as num_missing
from (select t.*,
lead(personid) over (order by personid) as next_personid
from t
) t
where next_personid <> personid + 1;
If you still want the list of ids, you can expand out the ranges, but that depends on the database.
In SQL Server 2008, this is much more performance intensive, but you can do it:
select personid + 1, tnext.personid - 1 as end_range,
text.personid - personid - 1 as num_missing
from t cross apply
(select top (1) t2.person_id
from t t2
where t2.personid > t.person_id
order by t2.personid asc
) tnext
where tnext.personid <> personid + 1;
I have two tables.
ItemRelation table having 30k records
ID ChildID1 ChildID2 ChildID3
------------------------------------------
9 null null null
49 43 50 //43 in childid1, don't want this record too
111 112 113 null
65 68 null null
222 221 223 224
79 null null null
5773 5834 5838 null
F_ItemDailySalesParent having millions of records
ItemID StoreId
-----------------
9 1001 //ItemID 9,41,5773 belongs to 1001 StoreID
41 1001
43 1400 //ItemID 43,45,65,5834 belongs to 1400 StoreID
45 1400
65 1400
68 2000 //ItemID 68,79 belongs to 2000 StoreID
79 2000
5773 1001
5834 1400
5838 2000
I want to show the record ID from ItemRelation table where the ItemID from F_ItemDailySalesParent not present in ItemRelation
ItemID StoreID
-----------------
49 1001
111 1001
65 1001
222 1001
79 1001
9 1400
111 1400
222 1400
79 1400
9 2000
49 2000
111 2000
222 2000
5773 2000
I tried this following query. But this will work without StoreID. But no idea for the above result
select ID from HQMatajer.dbo.ItemRelation ir
where not exists(
select ID,StoreID
from [HQWebMatajer].[dbo].[F_ItemDailySalesParent] Fid
where fid.ItemID=ir.ID
or fid.ItemID = ir.ChildID1
or Fid.ItemID=ir.ChildID2
or Fid.ItemID=ir.ChildID3
and time between '2017-01-01 00:00:00.000' and '2017-02-28 00:00:00.000'
group by ItemID,StoreID
)
Update
I have Hqmatajer.dbo.Store that column name of storeCode = F_ItemDailySalesParent.Storeid
Include checking if StoreId matches when using the not exists()
select ID
from HQMatajer.dbo.ItemRelation ir
cross join (select distinct storeCode from Hqmatajer.dbo.Store) s
where not exists(
select 1
from [HQWebMatajer].[dbo].[F_ItemDailySalesParent] Fid
where fid.StoreId = s.StoreCode
and [time] between '2017-01-01 00:00:00.000' and '2017-02-28 00:00:00.000'
and ( fid.ItemID=ir.ID
or fid.ItemID=ir.ChildID1
or Fid.ItemID=ir.ChildID2
or Fid.ItemID=ir.ChildID3
)
)
If I understand correctly, you want to start with a list of all stores and items and then filter out the ones that are present.
select i.id, s.storeId
from (select distinct id from HQMatajer.dbo.ItemRelation ir) i cross join
stores s -- assume this exists
where not exists (select 1
from [HQWebMatajer].[dbo].[F_ItemDailySalesParent] idsp
where idsp.ItemID = i.ID and idsp.storeId = s.storeId
) and
not exists (select 1
from [HQWebMatajer].[dbo].[F_ItemDailySalesParent] idsp
where idsp.ItemID = i.childID1 and idsp.storeId = s.storeId
) and
not exists (select 1
from [HQWebMatajer].[dbo].[F_ItemDailySalesParent] idsp
where idsp.ItemID = i.childID2 and idsp.storeId = s.storeId
) and
not exists (select 1
from [HQWebMatajer].[dbo].[F_ItemDailySalesParent] idsp
where idsp.ItemID = i.childID3 and idsp.storeId = s.storeId
);
I did not include the time condition. It is not in your sample data, so it is unclear where it fits.
First get a unique list of ItemIds and unique list of StoreIDs, then you can see which are missing with a left join and a where cross ref table id is null. I'll do it in generic terms so you get the idea:
select s.StoreId, i.ItemId
from Stores s
cross apply Items i
left join ItemRelation ir
on s.StoreId = ir.StoreId
and i.ItemId = ir.ItemId
where ir.Id is null
I have a table like this
id Marca CodCartela Line Post status Time
---- ------ ----------- ---- ---- ------ -----------------------
178 346 4516645709 AS01 55 1 2015-04-05 02:30:12.627
179 346 4516645709 AS01 55 0 2015-04-05 02:31:23.593
180 346 4516645709 AS01 88 1 2015-04-05 02:32:05.107
181 346 4516645709 AS01 88 0 2015-04-05 02:32:22.060
Status 1 means IN and status 0 means OUT.
What I want is to display in and out time on the same line for each person.
Example
id Marca CodCartela Line Post status TimeIN TimeOUT
---- ---------------- ---- ---- ------ -----------------------------------------
178 346 4516645709 AS01 55 1 2015-04-05 02:30:12.627 2015-04-05 02:31:23.593
Is this possible or I need to rethink all the timekeeping aplications :(
This will track each person's Ins and Outs. Just switch yourTable in the CTE to your actual table name.
WITH CTE_yourTable
AS
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY Marca ORDER BY [Time]) activity_num
FROM yourTable
)
SELECT A.ID,
A.Marca,
A.CodCartela,
A.[Line],
A.[Post],
--A.[Status],
A.[Time] AS TimeIn,
B.[Time] AS [TimeOut]
FROM CTE_yourTable A
LEFT JOIN CTE_yourTable B
ON A.Marca = B.Marca
AND A.activity_num = B.activity_num - 1
WHERE A.[Status] = 1
Results:
ID Marca CodCartela Line Post TimeIn TimeOut
----------- ----------- --------------------------------------- ---- ----------- ---------------------- ----------------------
178 346 4516645709 AS01 55 2015-04-0502:30:12.627 2015-04-0502:31:23.593
180 346 4516645709 AS01 88 2015-04-0502:32:05.107 2015-04-0502:32:22.060
Its simple use conditional Aggregate.
SELECT marca,
codcartela,
line,
post,
Max(CASE WHEN status = 1 THEN time END) AS TimeIN,
Max(CASE WHEN status = 0 THEN time END) AS TimeOUT
FROM yourtable
GROUP BY marca,
codcartela,
line,
post
Assuming that the combination post, status is unique you can do a join:
select
t1.*
,t2.Time as timeOut
from tab t1
left join tab t2
on t1.post = t2.post
and t2.status = 0
where t1.status = 1
Otherwise you might have to add additional conditions.
I don't know exactly how is the schema structure, and didn't get you well, I'm not sure but according to your sample data and desired output I think you want something like this:
select t1.marca,
t1.codcartela,
t1.line,
t1.post,
t1.time as TimeIN,
t2.time as TimeOUT
FROM table_name t1
LEFT OUTER JOIN table_name t2 on t1.post=t2.post
and t1.marca = t2.marca
WHERE t1.status=1 and isnull(t2.status,0)=0
Edit: changed join column to marca as mentioned it is for person
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
I have one sql server (2008) table containing group of data.
Source PersonId Date Description Code IsDup
------ -------- ----- ----------- ------ -----
EHR 1234 1/1/2012 Fever 120.12
EHR 1234 6/1/2012 Fracture 101.00
EHR 1234 11/4/2012 Hypertension 223.15
RAM 1234 1/1/2012 Fever 120.12 <-- Duplicate
RAM 1234 6/1/2012 Fracture 101.00 <-- Duplicate
RAM 1234 4/1/2012 Diabetic 601.00
TAR 1234 2/1/2012 Asthma 456.00
TAR 1234 1/1/2012 Fever 120.12 <-- Duplicate
I need to compare the data between the different groups. "EHR" being the master group, I need to check if any other group has data exactly matching that in "EHR" master group within the table. And then it should update the IsDup column with 1.
Expected Result:
Source PersonId Date Description Code IsDup
------ -------- ----- ----------- ------ -----
EHR 1234 1/1/2012 Fever 120.12
EHR 1234 6/1/2012 Fracture 101.00
EHR 1234 11/4/2012 Hypertension 223.15
RAM 1234 1/1/2012 Fever 120.12 1
RAM 1234 6/1/2012 Fracture 101.00 1
RAM 1234 4/1/2012 Diabetic 601.00
TAR 1234 2/1/2012 Asthma 456.00
TAR 1234 1/1/2012 Fever 120.12 1
I know how to check for duplicates within the table but not sure how can we do comparison keeping one group static.
I got this from one of the stackoverflow thread to identify dups but how to add grouped comparision:
with x as (select *, rn = row_number()
over(PARTITION BY [PersonId], [Date], [Description], [Code] order by [PersonId], [Date], [Description], [Code])
from Results)
select * from x
where rn > 1
You can update your table using self join :
update r1 set isDup = 1
from results r1 join results r2 on
r1.PersonId = r2.PersonId and r1.Date = r2.Date and
r1.Description = r2.Description and r1.Code = r2.Code
where r1.Source <> 'EHR' and r2.Source = 'EHR'
This should do:
UPDATE A
SET IsDup = 1
FROM YourTable A
WHERE [Source] != 'EHR'
AND EXISTS (SELECT 1 FROM YourTable
WHERE [Source] = 'EHR'
AND PersonId = A.PersonId
AND [Date] = A.[Date]
AND Description = A.Description
AND Code = A.Code)
Here is a demo for you to try.
Try this:
;With rootQuery as
(
Select SOURCE, PersonId, Date, Description, Code
From MedicalHistory
Where Source = 'EHR'
)
Update mhd
Set IsDuplicate = 1
From rootquery mh
Join MedicalHistory mhd on mh.PersonId = mhd.PersonId
Where mh.Description = mhd.Description
And mh.Code = mhd.Code
And mh.Date = mhd.Date
And mhd.Source != 'EHR'
Try this please..
update tab
set tab1.isDup=1
from table1 tab1, table1 tab2
where
tab1.PersonId=tab1.PersonId and
tab1.Date=tab2.Date and
tab1.desription=tab2.desription and
tab1.Code=tab2.Code and
tab1.Source != tab2.source