DimDate Join to Another Table - sql

I have a DimDate table that I want to join to another table with dates where various visits took place. I have followed many threads on here, but I can't get the missing dates to appear in my result set. Attached is a screenshot of my DimDate table and below is the script. I have two versions with the Dimdate table being the main table and the other version with it as a left join to the other table, and neither bring through the missing dates in my result set. Basically, I am trying to bring through all months and populate with a NULL if there are no entries in my other table.
SELECT
month(d.date) as 'DimDateMonth'
,month(s.date) as 'ActivityMonth'
,year(d.date) as 'DimDateYear'
,[PCN]
,[Type of Visit]
,[Pharmacist]
,[Practice]
,count(distinct(cast(s.Date as date))) 'Number of visits'
FROM [dbo].[DimDate] as d
left join [dbo].[mytable] s on month(d.date) = month(s.date) and year(s.date) = year(d.date)
where s.Pharmacist = 'abc' and year(d.date) = '2020'
group by
month(d.date)
,month(s.date)
,year(d.date)
,[PCN]
,[Type of Visit]
,[Pharmacist]
,[Practice]

Filters on the second table in a LEFT JOIN need to be in the ON clause:
FROM [dbo].[DimDate] d LEFT JOIN
[dbo].[mytable] s
ON month(d.date) = month(s.date) AND
year(s.date) = year(d.date) AND
s.Pharmacist = 'abc'
WHERE year(d.date) = '2020'
Putting the s.Pharmacist = 'abc' in the WHERE clause filters out NULL values -- which undoes the LEFT JOIN.
Note that conditions on the first table should still go in the WHERE clause so the rows really are filtered out.
I would also recommend writing the WHERE clause as:
WHERE d.date >= '2020-01-01' AND
d.date < '2021-01-01'
This allows the query to use and index on (date) for filtering.

Related

Left join in view with condition on the left table but still want all records

I have a date dimension table from which I want to left join to another table in order to show records (worker_availability) that exist for dates for the next couple weeks, for instance.
Date Dimension simply has every date for the next hundred years.
SELECT
dd.date_actual,
wa.worker_id,
string_agg(sh.name, ', ')
FROM public.worker_availability wa
LEFT JOIN public.d_date dd on wa.day = dd.date_actual --and wa.worker_id = '00000000-0000-0000-0000-000000000000'
LEFT JOIN public.shift sh on sh.shift_id = wa.shift_id
where
wa.worker_id = '00000000-0000-0000-0000-000000000000' AND
dd.date_actual >= NOW()
GROUP BY dd.date_actual, wa.worker_id
ORDER BY dd.date_actual asc
LIMIT 100
If I violate a principle of left join and use a where, then the results are incorrect.
If I add WHERE (worker_id = '00000000-0000-0000-0000-000000000000' OR wa.* IS NULL) then the results are still incorrect.
I want to see every date regardless of if there is a worker_availability record for the date.
The issue is that if I filter the left worker_availability left join (which works), then I can no longer make this query into a view and use it from EntityFramework because I cannot use the worker_id column in a where clause.

Return null values in GROUP BY query

This only returns results for entries that exist, which makes sense, but I'm trying to get it to display all of the B.[HostName] entries, even if there aren't entries for all of them. I'd like it to show 0 under the count for those. I've read about needing to use a LEFT JOIN on some of the tables and changing the COUNT(*) to use a field instead, but whenever I have tried that, it still results in the same data. Can anyone show me what would need to be changed for this to work the way I mentioned?
EDIT:
To clarify, since the initial answers didn't work:
The count would be coming from this table: [Database].[dbo].[WorkItemHistory] A -- we want all of the entries of A.[PlatformId]
A.[PlatformId] is a foreign key to C.[Id]
AND C.[EngineId] is a foreign key to B.[Id]
From there, we are getting B.[HostName]
So, all entries for B.[HostName] would be listed in the output and the count would come from the entries in the A.[WorkitemHistory] table.
We are using
SELECT DISTINCT B.[HostName], COUNT(*) AS Count
FROM [Database].[dbo].[WorkItemHistory] A, [Database].[dbo].[Engine] B, [Database].[dbo].[Platforms] C
WHERE A.[PlatformId] = C.[Id]
AND B.[Id] = C.[EngineId]
AND A.[Status] = '30'
AND A.[LastAttemptDateTime] >= CAST(GETDATE() AS Date)
GROUP BY B.[HostName]
ORDER BY COUNT(*) DESC
Replace your JOIN with a RIGHT JOIN B like below
to give values of B that doesnt have any common values of B in others.
SELECT B.[HostName], COUNT(*) AS Count
FROM [Database].[dbo].[WorkItemHistory] A
JOIN [Database].[dbo].[Platforms] C
On A.[PlatformId] = C.[Id]
RIGHT JOIN [Database].[dbo].[Engine] B
On C.[id]=B.[EngineId]
Where A.[Status] = '30'
AND A.[LastAttemptDateTime] >= CAST(GETDATE() AS Date)
GROUP BY B.[HostName]
ORDER BY COUNT(*) DESC
I think Something like this will do it. You just need to left join the other tables to [Database].[dbo].[Engine] since you want all the hostnames.
SELECT B.[HostName],
COUNT(C.ID) AS Count
FROM [Database].[dbo].[Engine] B
LEFT JOIN [Database].[dbo].[Platforms] C
ON B.[Id] = C.[EngineId]
LEFT JOIN [Database].[dbo].[WorkItemHistory] A
ON A.[PlatformId] = C.[Id]
AND A.[Status] = '30'
AND AND A.[LastAttemptDateTime] >= CAST(GETDATE() AS Date)
GROUP BY B.[HostName]
ORDER BY COUNT(*) DESC

How To Display Customers Even If They Have No Sales (results)

I have a code that pulls all of a Reps new customers and their year to date sales. The only problem is it only pulls customers that have sales in the invdate range, but I need it to show all of the accounts with a 0 if they do not have any sales. Is there any way to achieve this? I tried using COALESCE and it didn't seem to work. I also tried using left, right, full outer joins. Any help would be appreciated!
select
a.Acctnum,
sum(a.invtotal) as total
from invoices a right join accounts b on a.acctnum = b.acctnum where
a.invdate between '1/1/2017' and '12/31/2017'
and a.sls = '78'
and b.sls = '78'
and b.activetype = 'y' and b.startdate > (getdate()-365)
group by a.acctnum
order by total desc
You are restricting your results in your WHERE clause AFTER you join your table causing records to drop. Instead, switch to a LEFT OUTER JOIN with your accounts table driving the query. Then restrict your invoices table in your ON clause so that invoices are dropped BEFORE you join.
SELECT a.Acctnum,
sum(a.invtotal) AS total
FROM accounts b
LEFT OUTER JOIN invoices a ON
a.accntnum = b.acctnum AND
--Put the restrictions on your left most table here
--so they are removed BEFORE joining.
a.invdate BETWEEN '1/1/2017' AND '12/31/2017'
AND a.sls = '78'
WHERE
b.sls = '78'
AND b.activetype = 'y'
AND b.startdate > (getdate() - 365)
GROUP BY a.acctnum
ORDER BY total DESC
It's a bit like doing a subquery in invoices before joining in as the left table. It's just easier to drop the conditions into the ON clause.
Your problem is you where clauses are changing the right join to an inner join. Put all the ones that are aliased by a. into the ON clause.

Need to understand specific LEFT OUTER JOIN behavior in SQL SELECT

I have two tables, transactions and dates. One date may have one or more transactions. I need to get a list of dates with or without transactions of a specific account (account number 111 below).
select d.the_date, t.account, t.amount from dates as d
LEFT OUTER JOIN transactions as t ON t.tx_date=d.the_date
where t.account=111 AND d.the_date>='2016-01-02' and d.the_date<='2017-12-30'
order by d.the_date;
The issue is that when I specify in the condition t.account=111 I don't get the dates on which account 111 did NOT make any transactions.
Only if I remove from the condition t.account=111 I DO get the dates with no transactions (i.e. the LEFT OUTER JOIN works). Why does this happen?
Conditions on the second table need to go into the on clause:
select d.the_date, t.account, t.amount
from dates d left join
transactions t
on t.tx_date = d.the_date and t.account = 111
where d.the_date >= '2016-01-02' and d.the_date <= '2017-12-30'
order by d.the_date;
Otherwise, the value of t.account is NULL in the where clause, turning the outer join into an inner join.

SQL Create dates between date range for multiple dimensions

I have two tables:
SELECT DISTINCT ServLine,RoomID,StartDt,EndDt
INTO #raw
FROM table
SELECT CALENDAR_DATE
INTO #cal
FROM caldendar
How would I write a query to show each CALENDAR_DATE from the #cal table that is in between each StartDt and EndDt for each RoomID and ServLine from the #raw table.
Thank you
With a join. Depending on exactly what input and desired output you have, the join may vary, but an inner join seems like a good place to start without more information.
select *
from #raw r
inner join #cal c
on c.date >= r.startdt
and c.date <= r.enddt