Join to table with a condition - sql-server

I have table of clients and I need to join to another table with two conditions.
For example in the join table I have cancellation table :
ID
timestamp
value
1555
1005
NULL
1555
NULL
NULL
1566
R*1005
NULL
1566
R*243
12
1566
R*4918
8305
10M95
R*9017
8305
10M95
R*9470
8221
I need to find a client id 156 that has timestamp not null and value that is not null of the same row so for example id 1566 would join but not 1555 also the join must return only one row
SELECT
client.createdon, client.id,
domain.paymentprofileid AS paymentprofileid
FROM
Clients AS client
JOIN
cancellation AS cancel ON client.id = cancel.customer_id
WHERE
cancel.timestamp IS NOT NULL
AND cancel.value IS NULL

I'm guessing from the context that by 156 you mean 1566.
If I understand correctly then you're looking for any rows in the client table that have 1 or more rows in the cancellation table with both a timestamp and value that are not null.
I've removed the reference to domain table.
SELECT
client.createdon,
client.id
FROM
Clients AS client
WHERE client.id in (
SELECT customer_id
FROM cancellation
WHERE timestamp IS NOT NULL
AND cancel.value IS NULL
)
Hope this helps, though its tough to be sure if this is what was meant by your question.
As previous posts have mentioned, please try and phrase your question clearly so it can be understood.

Related

Conditionally Change String Name

I have a large data source that's automatically uploaded in a SQL Server Table so I am unable to manually change the data. Every now and then there are records that are mislabeled. 98% of the dataset contains unique Patient_fins; however, for patients that have been to both locations (ED and EDU), Patient_fin are duplicated, which is fine. For example,
Patient_fin CHECKIN_DATE_TIME TRACKING_GROUP
1 2018-01-01 01:37:00 EDU
1 2018-01-01 04:37:00 ED
I'm running into issues when the patients tracking group is not correctly labeled (both labels are the same when the CHECKIN_DATE_TIMEs are different) . For example, I can tell from the CHECKIN_DATE_TIME that the patient has been to two different locations ED and EDU, yet the tracking group is the same. The second row for Patient_fin 1, tracking group should read 'ED'
Patient_fin CHECKIN_DATE_TIME TRACKING_GROUP
1 2018-01-01 01:37:00 EDU
1 2018-01-01 04:37:00 EDU
For instances where the TRACKING GROUP is incorrect, is there a way in SQL where I can recode the record with the later CHECKIN_DATE_TIME so the TRACKING_GROUP reads ED. A priori knowledge tells me the later CHECKIN_DATE_TIME will always be associated with ED and not EDU.
IF only there will ever be two records with the same Patient_fin and you don't need to account for the first record being ED, what happens then? You would then be left with two records having a TRACKING_GROUP = ED:
--This will do pretty much what Sean Lange described except instead of a cte, it uses
--A subquery to get the records with a row number, partitioned by the Patient_fin
--It then joins this on the table by Patient_fin and CHECKIN_DATE_TIME and updates the second record for a Patient_fin
UPDATE dbo.SomTable
SET TRACKING_GROUP = 'ED'
FROM dbo.SomeTable AS st
INNER JOIN
(
SELECT Patient_fin, CHECKIN_DATE_TIME, ROW_NUMBER() OVER(PARTITION BY Patient_fin ORDER BY Patient_fin) AS [RowNumer]
FROM dbo.SomeTable
) AS x
ON x.CHECKIN_DATE_TIME = st.CHECKIN_DATE_TIME AND x.Patient_fin = st.Patient_fin
WHERE x.RowNum = 2

T-SQL - joining a transaction table to an audit table

Say I have these two tables:
Transaction Table
Pmt ID VendorID PaymentDate
1 1 2017-10-01 00:14:42
2 2 2017-09-03 00:08:23
The second table has a list of those VendorIDs, and everytime the associated email changed. It could have changed tons of times.
Audit Table
VendorID Email CreateDateUTC
1 a#gmail.com 2016-01-01 17:51:08
1 b#gmail.com 2016-03-03 12:40:03
1 c#gmail.com 2017-01-10 03:40:04
2 li#gmail.com 2017-03-30 05:40:03
Edit: So say this would show that any payment that went to vendor id 1 after 2016-01-01 17:51:08 but before 2016-03-03 12:40:03 went to a#gmail.com. Any payment that went to vendor id 1 after 2016-03-03 12:40:03 but before 2017-01-10 03:40:04 went to b#gmail.com. And that anything to vendor id 1 that went after 2017-01-10 03:40:04 went to c#gmail.com (unless of course, there's another more recent entry for vendor 1 in the Audit Table).
If I say - wanted to know every transaction that went out to email example#gmail.com, how could I query that?
My assumption is I'd take the transaction table - then join the audit table. Then OK, we have every transaction, and the email it went to. But, how to join only the correct email? Or, am I maybe thinking about this the wrong way entirely?
You Have to create one vendor master in which only main distinct vendor is stored with unique id.
Then create a sub table vendor contact detail.In that add the more than on contact detail for the vendor created in the master and in vendor contact detail also insert one field isPrimary that is bifurcate the Vendor address to be chosen.
then make join and do the task
Need more info, but maybe this will work?
select distinct t.PmtID, t.VendorID, t.PaymentDate
from tblTrans t
inner join tblAudit a
on t.VendorID = a.VendorID
where t.PaymentDate <= a.CreateDateUTC
and a.Email = 'a#gmail.com'
order by t.PaymentDate
The following query returns all rows from transaction table and it matches audit table and gets the email ID to which the email has been sent at the time of transaction
SELECT * FROM
(
SELECT VENDOR.*,Audit.Email,ROW_NUMBER() OVER(PARTITION BY
Vendor.VendorID ORDER BY DATEDIFF(D,CreateDateUTC, PaymentDate) DESC) RNo
FROM Vendor LEFT OUTER JOIN Audit ON Vendor.VendorId =Audit.VendorId
WHERE PaymentDate > CreateDateUTC
)T
WHERE RNo = 1

SQL join conditional either or not both?

I have 3 tables that I'm joining and 2 variables that I'm using in one of the joins.
What I'm trying to do is figure out how to join based on either of the statements but not both.
Here's the current query:
SELECT DISTINCT
WR.Id,
CAL.Id as 'CalendarId',
T.[First Of Month],
T.[Last of Month],
WR.Supervisor,
WR.cd_Manager as [Manager], --Added to search by the Manager--
WR.[Shift] as 'ShiftId'
INTO #Workers
FROM #T T
--Calendar
RIGHT JOIN [dbo].[Calendar] CAL
ON CAL.StartDate <= T.[Last of Month]
AND CAL.EndDate >= T.[First of Month]
--Workers
--This is the problem join
RIGHT JOIN [dbo].[Worker_Filtered]WR
ON WR.Supervisor IN (SELECT Id FROM [dbo].[User] WHERE FullName IN(#Supervisors))
or (WR.Supervisor IN (SELECT Id FROM [dbo].[User] WHERE FullName IN(#Supervisors))
AND WR.cd_Manager IN(SELECT Id FROM [dbo].[User] WHERE FullNameIN(#Manager))) --Added to search by the Manager--
AND WR.[Type] = '333E7907-EB80-4021-8CDB-5380F0EC89FF' --internal
WHERE CAL.Id = WR.Calendar
AND WR.[Shift] IS NOT NULL
What I want to do is either have the result based on the Worker_Filtered table matching the #Supervisor or (but not both) have it matching both the #Supervisor and #Manager.
The way it is now if it matches either condition it will be returned. This should be limiting the returned results to Workers that have both the Supervisor and Manager which would be a smaller data set than if they only match the Supervisor.
UPDATE
The query that I have above is part of a greater whole that pulls data for a supervisor's workers.
I want to also limit it to managers that are under a particular supervisor.
For example, if #Supervisor = John Doe and #Manager = Jane Doe and John has 9 workers 8 of which are under Jane's management then I would expect the end result to show that there are only 8 workers for each month. With the current query, it is still showing all 9 for each month.
If I change part of the RIGHT JOIN to:
WR.Supervisor IN (SELECT Id FROM [dbo].[User] WHERE FullName IN (#Supervisors))
AND WR.cd_Manager IN(SELECT Id FROM [dbo].[User] WHERE FullName IN(#Manager))
Then it just returns 12 rows of NULL.
UPDATE 2
Sorry, this has taken so long to get a sample up. I could not get SQL Fiddle to work for SQL Server 2008/2014 so I am using rextester instead:
Sample
This shows the results as 108 lines. But what I want to show is just the first 96 lines.
UPDATE 3
I have made a slight update to the Sample. this does get the results that I want. I can set #Manager to NULL and it will pull all 108 records, or I can have the correct Manager name in there and it'll only pull those that match both Supervisor and Manager.
However, I'm doing this with an IF ELSE and I was hoping to avoid doing that as it duplicates code for the insert into the Worker table.
The description of expected results in update 3 makes it all clear now, thanks. Your 'problem' join needs to be:
RIGHT JOIN Worker_Filtered wr on (wr.Supervisor in(#Supervisors)
and case when #Manager is null then 1
else case when wr.Manager in(#Manager) then 1 else 0 end
end = 1)
By the way, I don't know what you are expecting the in(#Supervisors) to achieve, but if you're hoping to supply a comma separated list of supervisors as a single string and have wr.Supervisor match any one of them then you're going to be disappointed. This query works exactly the same if you have = #Supervisors instead.

UPDATE query to synchronize duplicated records

I have a number of duplicate records in a table, highly simplfied example is:
name, emailaddress, importantid
John Smith, john#smith.com, NULL
John Smith, john#smith.com, 12345
John Smith, john#smith.com, NULL
The problem comes later when another table is joined to this, it may be joined to one of the records which doesn't have the importantid I need.
I'm looking to update the table so that for each email address it finds the first one where importantid is not null and then updates the other records with that id, so all duplicate accounts end up having the important id.
How could I do that?
Thanks
SQL Fiddle Demo
UPDATE a
SET a.importantid = b.importantid
FROM test AS a
JOIN (SELECT emailaddress, max(importantid) as importantid
FROM test
GROUP BY emailaddress) AS b
ON a.emailaddress = b.emailaddress;
UPDATE yourTable t1
SET importanid =(SELECT max(importantid)
FROM yourTable t2
WHERE t2.emailaddress = t1.emailaddress AND t1.importantid is null and t2.importantid is not null)

Select query using NOT IN in SQL Server 2008

I have two tables Sales and Return:
Sales table:
DocNum ItemCode
101 itemcode1
101 itemcode2
102 itemcode3
102 itemcode2
Return table:
DocNum ItemCode
101 itemcode1
102-reject itemcode2
Desired output:
DocNum ItemCode
101 itemcode2
102 itemcode3
I need to select data from the Sales table that does not exist in the Return table, using a NOT IN condition. I only get records that match DocNum column on the two tables, my problem here is user put a word 'reject' on the Return table.
Is there a way to to match the docnum column in these situation?
You can achieve what you want using a LEFT JOIN:
SELECT s.DocNum
FROM Sales s LEFT JOIN Return r
ON s.DocNum = CASE WHEN CHARINDEX('-', r.DocNum) > 0
THEN SUBSTRING(r.DocNum, 1, CHARINDEX('-', r.DocNum)-1)
ELSE r.DocNum
END AND
s.ItemCode = r.ItemCode
WHERE r.DocNum IS NULL
By the way, you should rethink your database design and stop putting the word "reject" into an id column, which makes querying the table difficult. Instead, add a new boolean column called reject to keep track of this.
SELECT *
FROM Sales s
WHERE NOT EXISTS
(
SELECT *
FROM [Return] r
WHERE r.DocNum LIKE s.DocNum + '%'
)
As far as the question is concerned, the query below should return the expected output, even if the DocNum is set to something like "102/reject" or "102(reject)" or whatever.
select a.DocNum, a.ItemCode
from SalesTable a
left join ReturnTable b on charindex(a.DocNum, b.DocNum) > 0
and a.ItemCode = b.ItemCode
where b.DocNum is null
However, as far as sensible table design is concerned, allowing DocNum to be updated to 102-reject is a bad practice. This exposes a few design flaws:
DocNum is a varchar column instead of a more suitable integer column
Allowing user to manipulate what is obviously a key column may introduce SQL injection risks.
and what happens when DocNum is updated to "102-101"?

Resources