I have a 1:1 table (we will call this table 1) which looks like this:
| id | date |
|----|---------------------|
| 1 | 2011-01-02 00:00:00 |
| 2 | 2012-01-02 00:00:00 |
I have a second many:1 table (we will call this table 2) which looks like this:
| id | date |
|----|---------------------|
| 1 | 2011-01-01 00:00:00 |
| 1 | 2011-01-02 00:00:00 |
| 1 | 2011-01-03 00:00:00 |
| 2 | 2011-12-31 00:00:00 |
| 2 | 2012-01-01 00:00:00 |
| 2 | 2012-01-03 00:00:00 |
I would like to left join table 1 and table 2 (table 1 is the left table) on id, but I only want the count of dates from table 2 that are greater than or equal to the date column in table 1.
Thus, the resultant table would look like this:
| id | date | count_dates |
|----|---------------------|-------------|
| 1 | 2011-01-02 00:00:00 | 2 |
| 2 | 2012-01-02 00:00:00 | 1 |
How can I do this using SQL Server?
Don't bother with a left join, just use a sub-query with the appropriate where clause e.g.
select id, [date]
, (select count(*) from dbo.Table2 T2 where T2.id = T1.id and T2.[date] >= T1.[date])
from dbo.Table1 T1;
Related
I have two SQL Server tables as below:
Event
+------------+----------------------------+-------------+------------+-----------------------------+
| Id | EventTypeId | PersonId | UCNumber | Name |DateEvent
+------------+----------------------------+-------------+------------+-----------------------------+
| 2307 | 3 | 2189 | 004947 | Migrated | 1900-01-01 00:00:00.6780000 |
| 2308 | 15 | 2189 | 004947 | Birthday | 2020-09-18 16:48:32.6870000 |
| 3400 | 15 | 2190 | 006857 | Birthday | 1900-01-01 00:00:00.0000000 |
| 3401 | 2 | 2190 | 006857 | Migrated | 2016-03-12 00:00:00.0000000 |
Person
+------------+----------------+-------------------+-----------+-------------------------------+
| Id | UCNumber | Name |LastName | AnotherDate |
+------------+----------------+-------------------+-----------+-------------------------------+
| 2189 | 004947 | John | Smith | 1900-01-01 00:00:00.0000000 |
| 2190 | 006857 | Alice | Timo | 2020-02-20 00:00:00.0000000 |
I need to get retrieved the top row (latest in time) based on the Event's Id. (The higher the Id, the more recent the Event) and it should be a 15 as EventTypeId.
I tried this:
Select P.Id, P.UCNUMBER, P.AnotherDate from
db.dbo.Person P
Inner join db.dbo.Event L on L.PersonId = P.Id
where P.Id in (
SELECT TOP (1) PersonId
FROM
db.dbo.Event
where PersonId = P.Id --and EventTypeID = 15
ORDER BY
Id DESC)
and EventTypeId = 15
but it does not work properly. I posted here just samples from the 2 tables. Generally the query takes also other events which are not latest ones (as higher Id). Something is missing in it.
In this case, for instance, it should return only 1 row:
2189 004947 1900-01-01 00:00:00.0000000
Sounds like you just want ORDER BY and TOP 1.
SELECT TOP 1
p.id,
p.ucnumber,
p.anotherdate
FROM event e
LEFT JOIN person p
ON p.id = e.personid
WHERE e.eventtypeid = 15
ORDER BY e.dateevent DESC;
If you want all ties in case there are more events on the same latest time you can replace TOP 1 with TOP 1 WITH TIES.
I have got two tables 'Customer'.
The first one:
ID | UserID | Date
1. | 1 | 2018-05-01
2. | 1 | 2018-05-02
The second one:
ID | UserID | Date
1. | 1 | 2018-05-01
2. | 1 | 2018-05-02
3. | 1 | 2018-05-03
So, as you can see in the second table, there is one row more.
I have written so far this code:
;with cte_table1 as (
select UserID, count(id) cnt from db1.Customer group by UserID
),
cte_table2 as (
select UserID, count(id) cnt from db2.Customer group by UserID
)
select * from cte_table1 t1
join cte_table2 t2 on t2.UserID = t1.UserID
where t1.cnt <> t2.cnt
and this gives me expected result:
UserID | cnt | UserID | cnt
1 | 2 | 1 | 3
And so far, everything is fine. The thing is, these two tables have many rows and I'd like to have result with dates, where cnt does not match.
In other words, I'd like to have something like this:
UserID | cnt | Date | UserID | cnt | Date
1 | 2 | 2018-05-01 | 1 | 3 | 2018-05-01
1 | 2 | 2018-05-02 | 1 | 3 | 2018-05-01
1 | 2 | NULL | 1 | 3 | 2018-05-03
The best soulution would be resultset where both cte's are joined to give this:
UserID | cnt | Date | UserID | cnt | Date
1 | 2 | 2018-05-01 | 1 | 3 | 2018-05-01
1 | 2 | 2018-05-02 | 1 | 3 | 2018-05-01
1 | 2 | NULL | 1 | 3 | 2018-05-03
1 | 2 | 2018-05-30 | 1 | 3 | NULL
You should do a FULL OUTER JOIN query like below
Select
C1.UserID,
C1.cnt,
C1.Date,
C2.UserID,
C2.cnt,
C2.Date
from
db1.Customer C1
FULL OUTER JOIN
db2.Customer C2
on C1.UserId=C2.UserId and C1.date=C2.Date
From my table, I want to select for each project ID the ID with the latest deploymentDate and if there are two identical latest deployment dates for the same project ID, select the ID with the latest submittedOn datetime. So if my table looks like this:
id | projectId | deploymentDate | submittedOn |
1 | 1 | 2017-01-02 | 2017-01-02 13:00:00 |
2 | 1 | 2017-01-04 | 2017-01-04 11:00:00 |
3 | 2 | 2017-01-06 | 2017-01-06 17:00:00 |
4 | 2 | 2017-01-06 | 2017-01-01 12:00:00 |
5 | 3 | 2017-01-02 | 2017-01-02 13:30:00 |
6 | 3 | 2017-01-02 | 2017-01-05 15:00:00 |
7 | 3 | 2017-01-02 | 2017-01-04 10:00:00 |
The desired rows are:
id | projectId | deploymentDate | submittedOn |
2 | 1 | 2017-01-04 | 2017-01-04 11:00:00 |
3 | 2 | 2017-01-06 | 2017-01-06 17:00:00 |
6 | 3 | 2017-01-02 | 2017-01-05 15:00:00 |
You can try the below. Adjust the sorting in the row_number as needed.
select
a.id,
a.projectid,
a.deploymentdate,
a.submittedOn
from project a
inner join
(select
a.id,
row_number() over (partition by projectid order by deploymentdate desc, submittedOn desc, id) as rid
from project
) as b
on b.id = a.id
and b.rid = 1
This would work:
select t.id, latest.*
from tab t join (
select projectid, max(deploymentdate) deploymentdate, max(submittedon) submittedon
from tab
group by projectid
) latest on t.projectid = latest.projectid and t.deploymentdate = latest.deploymentdate and t.submittedon = latest.submittedon
I found the latest based on the project id and then, joined with the source table to find the corresponding id.
I want to 'clean' a dataset and declare a new variable, then input a date based on rank.
My dataset looks like this:
+-----+--------------+------------+-------+
| ID | Start_date | End_date | Rank |
+-----+--------------+------------+-------+
| a | May '16 | May '16 | 5 |
| a | Jun '16 | Jul '16 | 4 |
| a | Jul '16 | Aug '16 | 3 |
| a | Aug '16 | NULL '16 | 2 |
| a | Sept '16 | NULL '16 | 1 |
+-----+--------------+------------+-------+
I basically want to input the start date of rank 1 into the end date of rank 2 or say input start 5 into end 6 (always -1).
Have written the following to select into a tempory table and rank based on id and date:
SELECT
[Start_Date] as 'start'
,[End_Date] as 'end'
,[Code] as 'code'
,[ID] as 'id'
,rank() over (partition by [id] order by [Start_Date]) as 'rank'
INTO #1
FROM [Table]
ORDER BY [id]
Its the following part that doesn't work ...
DECLARE new_end
BEGIN select [#1].[start] into new_end FROM [#1]
WHERE (
([#1].[rank] = 1)
AND ([#1].[end] IS NULL)
)
Assuming you already have your dataset as provided in your question, this is just a simple self join, no?
declare #t table(ID nvarchar(1), Start_date date, End_date date, [Rank] int);
insert into #t values ('a','20170501','20170501',5),('a','20170601','20170701',4),('a','20170701','20170801',3),('a','20170801',NULL,2),('a','20170901',NULL,1);
select t1.ID
,t1.Start_date
,isnull(t1.End_date,t2.Start_date) as End_date
-- If you *always* want to overwrite the End_Date use this instead:
-- ,t2.Start_date as End_date
,t1.[Rank]
from #t t1
left join #t t2
on(t1.[Rank] = t2.[Rank]+1);
Output:
+----+------------+------------+------+
| ID | Start_date | End_date | Rank |
+----+------------+------------+------+
| a | 2017-05-01 | 2017-05-01 | 5 |
| a | 2017-06-01 | 2017-07-01 | 4 |
| a | 2017-07-01 | 2017-08-01 | 3 |
| a | 2017-08-01 | 2017-09-01 | 2 |
| a | 2017-09-01 | NULL | 1 |
+----+------------+------------+------+
I'm relatively new to SQL and am running into a lot of issues trying to figure this one out. I've tried using a LEFT JOIN, and dabbled in using functions to get this to work but to no avail.
For every UserID, if there is a NULL value, I need to remove all records of the Product ID for that UserID from my SELECT.
I am using SQL Server 2014.
Example Table
+--------------+-------------+---------------+
| UserID | ProductID | DateTermed |
+--------------+-------------+---------------+
| 578 | 2 | 1/7/2017 |
| 578 | 2 | 1/7/2017 |
| 578 | 1 | 1/15/2017 |
| 578 | 1 | NULL |
| 649 | 1 | 1/9/2017 |
| 649 | 2 | 1/11/2017 |
+--------------+-------------+---------------+
Desired Output
+--------------+-------------+---------------+
| UserID | ProductID | DateTermed |
+--------------+-------------+---------------+
| 578 | 2 | 1/7/2017 |
| 578 | 2 | 1/7/2017 |
| 649 | 1 | 1/9/2017 |
| 649 | 2 | 1/11/2017 |
+--------------+-------------+---------------+
Try the following:
SELECT a.userid, a.productid, a.datetermed
FROM yourtable a
LEFT OUTER JOIN (SELECT userid, productid, datetermed FROM yourtable WHERE
datetermed is null) b
on a.userid = b.userid and a.productid = b.productid
WHERE b.userid is not null
This will left outer join all records with a null date to their corresponding UserID and ProductID records. If you only take records that don't have an associated UserID and ProductID in the joined table, you should only be left with records that don't have a null date.
You can use this WHERE condition:
SELECT
UserID,ProducID,DateTermed
FROM
[YourTableName]
WHERE
(CONVERT(VARCHAR,UserId)+
CONVERT(VARCHAR,ProductID) NOT IN (
select CONVERT(VARCHAR,UserId)+ CONVERT(VARCHAR,ProductID)
from
[YourTableName]
where DateTermed is null)
)
When you concatenate the UserId and the ProductId get a unique value for each pair, then you can use them as a "key" to exclude the "pairs" that have the null value in the DateTermed field.
Hope this help.