I am trying the following but its throwing an error, can someone tell me what I am doing wrong?
SELECT custType, count(*)
FROM tbl1 a
LEFT JOIN tbl2 b ON a.tbID = b.tbID
AND ((CustType IN ('Apple','IPAD') and date BETWEEN #StartDate AND #EndDate)
or (CustType IN ('Samsung','LCD') and date BETWEEN #StartDateLL AND #EndDateLL))
GROUP BY CustType
Why don't use AND/OR
SELECT CustType , count(*)
FROM tbl1 a
LEFT JOIN tbl2 b ON a.tbID = b.tbID
AND ((CustType IN ('Apple','IPAD') and date BETWEEN #StartDate AND #EndDate)
or (CustType IN ('Samsung','LCD') and date BETWEEN #StartDateLL AND #EndDateLL))
group by CustType ;
EDIT You can't group by CustType and Select *
You cannot use a BETWEEN operator for the THEN part of a case statement or IIF. BETWEEN is the condition that translates to true and false. So it is VALUE BETWEEN A AND B and would be apart of the WHEN section of a case statement.
Also the case statement returns a value not a formula to be further executed.
I agree with #Vercelli's solution but to show you how a case statement works in the method you are trying you could do the following:
SELECT *
FROM tbl1 a
LEFT JOIN tbl2 b ON a.tbID = b.tbID
AND (CASE
WHEN CustType IN ('Apple','IPAD') AND [date] ETWEEN #StartDate AND #EndDate THEN 1
WHEN CustType IN ('Samsung','LCD') AND [date] BETWEEN #StartDateLL AND #EndDateLL THEN 1
ELSE 0 END) = 1
Again go with #vercelli's answer as it is the more appropriate way of writing the SQL query.
Related
In my searching for answers, I seem to only be finding explanations that cover the existence of NULL which is why the NOT IN returns 0 results. However, my scenario is exactly the opposite. I'm getting my expected results with the NOT IN and my NOT EXISTS is giving me 0. And to clarify, I have no NULLs in my sub-query. Here is my query:
DECLARE #EndDate DATE= CAST(CONCAT(YEAR(GETDATE()), '-', MONTH(GETDATE()), '-01') AS DATE) --First day of this month
DECLARE #StartDate DATE= DATEADD(month, -12, #EndDate) --12 months prior
SELECT Deactivated = COUNT(DISTINCT o.ClinicLocationId)
FROM [order].package p WITH(NOLOCK)
INNER JOIN [order].[order] o WITH(NOLOCK) ON o.packageid = p.packageid
INNER JOIN profile.ClinicLocationInfo cli WITH(NOLOCK) ON cli.LocationId = o.ClinicLocationId
AND cli.FacilityType IN('CLINIC', 'HOSPITAL')
WHERE CAST(p.ShipDTM AS DATE) >= dateadd(month,-1,#StartDate)
AND CAST(p.ShipDTM AS DATE) < dateadd(month,-1,#EndDate)
AND p.isshipped = 1
AND o.IsShipped = 1
AND ISNULL(o.iscanceled, 0) = 0
and not exists (
--and o.ClinicLocationId not in (
SELECT DISTINCT o.ClinicLocationId
FROM [order].package p WITH(NOLOCK)
INNER JOIN [order].[order] o WITH(NOLOCK) ON o.packageid = p.packageid
INNER JOIN profile.ClinicLocationInfo cli WITH(NOLOCK) ON cli.LocationId = o.ClinicLocationId
AND cli.FacilityType IN('CLINIC', 'HOSPITAL')
WHERE CAST(p.ShipDTM AS DATE) >= #StartDate
AND CAST(p.ShipDTM AS DATE) < dateadd(day,-1,#EndDate)
AND p.isshipped = 1
AND o.IsShipped = 1
AND ISNULL(o.iscanceled, 0) = 0
)
For a high level overview, I'm basically trying to find the number of ID's that exist in one set that don't in the next (separated by a 12 month rolling window, offset by 1 month). But for the sake of simplicity, I've written the below that very simply illustrates the exact same symptom:
drop table if exists #T1, #T2
create table #T1 (id int)
create table #T2 (id int)
insert into #T1 (id)
values
(3),
(8)
insert into #T2 (id)
values
(671),
(171)
select id from #T1 where id not in (select id from #T2)
select id from #T1 where not exists (select id from #T2)
My expectation is that both of these would yield the same results, the contents of #T1 (3,8) but instead, I only get those results in the second query by eliminating the NOT. I would assume I'm suffering from a fundamental misunderstanding of how the EXISTS operator works, as up until now I assumed there was no real difference aside from how the scanning occurred and NULL handling.
Where am I going wrong with my expectation?
The query shape...
and o.ClinicLocationId not in (SELECT o.ClinicLocationId ...)
...correlates o.ClinicLocationId to o.ClinicLocationId in the subquery.
When using exists you have to write a correlated subquery to get the same effect:
and not exists (SELECT o1.ClinicLocationId ...
AND o1.ClinicLocationId = o.ClinicLocationId)
Note that the second query requires a different alias in the subquery.
I have the following query where I input a date and it give me the result. However, I need to run this for 60 different dates. Instead of running this 1 by 1, is there anyway to automate this so it runs each time on a different date?
IF OBJECT_ID('tempdb..#1') IS NOT NULL DROP TABLE #1
declare #d1 datetime = '2020-02-06'
select distinct [User] into #1
from [X].[dbo].[Table1]
where [status] = 'Success'
and [Date] = #d1;
select count(distinct [User])
from #1
inner join [Y].[dbo].[Table2]
on #1.[User] = [Y].[dbo].[Table2].User
where [Date2] between #d1 and #d1+1
and [Checkname] in ('Check1','Check2')
Loops are slow and generally a bad practice in the context of T-SQL. You can use something like this to get the count of users for a batch of dates:
DROP TABLE IF EXISTS #DataSource;
CREATE TABLE #DataSource
(
[Date] DATETIME
,[UsersCount] INT
);
INSERT INTO #DataSource ([Date])
VALUES ('2020-02-06')
,('2020-02-07')
,('2020-02-08');
IF OBJECT_ID('tempdb..#1') IS NOT NULL DROP TABLE #1
select distinct DS1.[Date]
,DS1.[User]
into #1
from [X].[dbo].[Table1] DS1
INNER JOIN #DataSource DS2
ON DS1.[Date] = DS2.[Date]
where DS1.[status] = 'Success';
select #1.[date]
,count(distinct [User])
from #1
inner join [Y].[dbo].[Table2]
on #1.[User] = [Y].[dbo].[Table2].User
where [Date2] between #1.[date] and #1.[date] + 1
and [Checkname] in ('Check1','Check2')
GROUP BY #1.[date]
First, I want to say that gotqn's answer is a good answer - however, I think there are a few more things in the original code that can be improved - so here is how I would probably do it:
Assuming the dates are consecutive, use a common table expression to calculate the dates using dateadd and row_number.
Then, use another common table expression to get the list of dates and users from table1,
and then select the date and count of distinct users for each date from that common table expression joined to table2:
DECLARE #StartDate Date = '2020-02-06';
WITH Dates AS
(
SELECT TOP (60) DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY ##SPID) -1, #StartDate) As Date
FROM sys.objects
), CTE AS
(
SELECT t1.[User], t1.[Date]
FROM [X].[dbo].[Table1] AS t1
JOIN Dates
ON t1.[Date] = Dates.[Date]
WHERE [status] = 'Success'
)
SELECT cte.[Date], COUNT(DISTINCT [User])
FROM CTE
JOIN [Y].[dbo].[Table2] As t1
ON CTE.[User] = t1.[User]
AND t1.[Date2] >= CTE.[Date]
AND t1.[Date2] < DATEADD(Day, 1, CTE.[Date])
AND [Checkname] IN ('Check1','Check2')
GROUP BY cte.[Date]
If the dates are not consecutive, you can use a table variable to hold the dates instead of calculating them using a common table expression.
In SQL server (2016), I want to convert 2 rows into 1 row with fields of both rows.
I have this example:
IF OBJECT_ID('tempdb.dbo.#MyTable') IS not NULL DROP TABLE #MyTable
CREATE TABLE #MyTable (
Direction varchar(1),
DateKey int,
ID varchar(8),
[Sessions] int
)
insert into #MyTable values('S', 20180301, 'ID123456', 46)
insert into #MyTable values('R', 20180301, 'ID123456', 99)
select * from #MyTable
Output:
Direction DateKey ID Sessions
S 20180301 ID123456 46
R 20180301 ID123456 99
The output I want is:
DateKey ID S_Sessions R_Sessions
20180301 ID123456 46 99
So I tried this query but it won't work:
select DateKey,ID,
case Direction
when 'S' then [Sessions] as S_Sessions -- Incorrect syntax near the keyword 'as'.
else [Sessions] as R_Sessions
end
from #MyTable
Maybe I have to create an extra table, insert rows where direction='S' and then update the records with data where direction='R' but I wonder if there is a better way to do this.
use PIVOT
select *
from #MyTable
pivot
(
max(Sessions)
for Direction in ([S], [R])
) p
assuming that your table contains the "pairs" S and R you can also use a self join
SELECT s.DateKey , s.ID , s.Sessions S_Sessions , r.Sessions R_Sessions
FROM #MyTable S
JOIN #MyTable R
ON s.ID = r.ID
AND s.DateKey = r.DateKey
WHERE S.Direction = 'S'
AND r.Direction = 'R'
CASE in SQL is an expression that returns a single value. It cannot be used to control execution flow like in procedural languages.
You can use conditional aggregation for this:
select DateKey, ID,
max(case Direction when 'S' then [Sessions] end) as S_Sessions,
max(case Direction when 'R' then [Sessions] end) as R_Sessions
from #MyTable
group by DateKey, ID
Demo here
Try It ... It works for me . more variable more case and more left join table.
select a.DateKey,a.ID,
(case a.Direction
when 'S' then a.Sessions
end) as S_Sessions,
(case b.Direction
when 'R' then b.Sessions
end) as R_Sessions
from mytable as a CROSS JOIN mytable as b ON a.ID=b.ID LIMIT 2,1
I am new and learning SQL on Microsoft SQL Server 2008. I am trying to do the following for a table of order line items each record is one order item.
any transaction numbers with only one record and a code of #####.
I have tried many ways but haven't been able to figure it out
Select * from Table
where count(transactionnumber)<2 and Code='9987'
I think I got it. Had to use a different code because QA didn't have an distinct rows with that code. Let me know if you see anything that might cause and issue.
Select * from (select Orders.TransactionNumber from Orders
group by Orders.TransactionNumber
having COUNT (Orders.TransactionNumber)=1) as transa
Inner join Orders on transa.TransactionNumber=Orders.TransactionNumber
where ItemCode=9803
Ended up with this code
use XXX
Select Orders.TransactionNumber,Orders.RepNumber, Orders.CustomerID,Orders.ShipToId,orders.ItemCode,Orders.Quantity,Orders.ReceivedDate,Orders.TransmitStatus from (select TransactionNumber from Orders
group by TransactionNumber
having COUNT (TransactionNumber)=1) as transa
Inner join Orders on Orders.TransactionNumber=transa.TransactionNumber
where ItemCode=9987 and ReceivedDate > DateADD (day, -1, GetDate() )
IF ##ROWCOUNT > 0
BEGIN
EXEC msdb.dbo.sp_send_dbmail
recipients=N'XXXX',
#body='Merchandisers orders with only Item Code 9803',
#subject ='only Item Code 9803',
#profile_name ='',
#query = 'Select Orders.TransactionNumber,Orders.RepNumber,Orders.CustomerID,Orders.ShipToId,orders.ItemCode,Orders.Quantity,Orders.ReceivedDate,Orders.TransmitStatus from(select TransactionNumber from Orders
group by TransactionNumber
having COUNT (TransactionNumber)<2) as transa
Inner join Orders on Orders.TransactionNumber=transa.TransactionNumber
where ItemCode=9803 and ReceivedDate > DateADD (day, -1, GetDate() )'
END'
Your query should include something to group by (Name, TransactionNumber, etc.) do a count and constrain on that.
SELECT TransactionCode, COUNT(*)
FROM TABLE
GROUP BY TransactionCode
HAVING COUNT(*) < 2
AND ItemCode = 9987
You may consider using the OVER keyword, so that you don't need to muck around the count(*) and group by so much. That way you can see counts without grouping.
Select *, count(*) over (partition by transactioncode) as "TheCounts"
from table
--where itemcode = 9903
or
Select *, count(*) over (partition by transactioncode, itemcode) as "TheCounts"
from table
--where itemcode = 9903
Here is what I ended up with on this that seems to be working correctly for about a week now it executes a sp_send_dbmail only if there are records.
Select Orders.TransactionNumber, Orders.RepNumber, Orders.CustomerID,Orders.ShipToId,orders.ItemCode,Orders.Quantity,Orders.ReceivedDate,Orders.TransmitStatus from (select TransactionNumber from Orders
group by TransactionNumber
having COUNT (TransactionNumber)=1) as transa
Inner join Device_Orders on Orders.TransactionNumber=transa.TransactionNumber
where ItemCode=9987 and ReceivedDate > DateADD (day, -1, GetDate() )
IF ##ROWCOUNT > 0
Im getting Invalid Column Name 'Average'. When Im writing without alias name it work. But I have too much condition.
SELECT
ST_LAWERP_PERFORMANCE_EVALUATION_ENTRIES.EMPLOYEEID,
Employees.EMPLOYEENAMESURNAMEFORMAT AS LastFirstName,
(CAST(SUM(EVALUATION) AS FLOAT)
/
(SELECT TOP 1
COUNT(*)
FROM ST_LAWERP_PERFORMANCE_EVALUATION_ENTRIES
WHERE DATE BETWEEN '2013-01-01' AND '2013-12-12' AND TYPE=2 AND SUPERVISORID=1020 GROUP BY EmployeeID )) AS AVERAGE,
CASE WHEN AVERAGE=1
THEN 'GOOD' END AS EVALUATION
FROM ST_LAWERP_PERFORMANCE_EVALUATION_ENTRIES INNER JOIN Employees
ON ST_LAWERP_PERFORMANCE_EVALUATION_ENTRIES.EMPLOYEEID=Employees.EmployeeID
WHERE DATE BETWEEN '2013-01-01' AND '2013-12-12' AND TYPE=2 AND ST_LAWERP_PERFORMANCE_EVALUATION_ENTRIES.SUPERVISORID=1020 AND ACTIVESTATUS=1
GROUP BY
ST_LAWERP_PERFORMANCE_EVALUATION_ENTRIES.EMPLOYEEID,
EMPLOYEENAMESURNAMEFORMAT
Try THis
SELECT *,case when average =1 then 'good' end as evaluation from(
select
ST_LAWERP_PERFORMANCE_EVALUATION_ENTRIES.EMPLOYEEID,
Employees.EMPLOYEENAMESURNAMEFORMAT AS LastFirstName,
(CAST(SUM(EVALUATION) AS FLOAT)
/
(SELECT TOP 1
COUNT(*)
FROM ST_LAWERP_PERFORMANCE_EVALUATION_ENTRIES
WHERE DATE BETWEEN '2013-01-01' AND '2013-12-12' AND TYPE=2 AND SUPERVISORID=1020 GROUP BY EmployeeID )) AS AVERAGE
FROM ST_LAWERP_PERFORMANCE_EVALUATION_ENTRIES INNER JOIN Employees
ON ST_LAWERP_PERFORMANCE_EVALUATION_ENTRIES.EMPLOYEEID=Employees.EmployeeID
WHERE DATE BETWEEN '2013-01-01' AND '2013-12-12' AND TYPE=2 AND ST_LAWERP_PERFORMANCE_EVALUATION_ENTRIES.SUPERVISORID=1020 AND ACTIVESTATUS=1
GROUP BY
ST_LAWERP_PERFORMANCE_EVALUATION_ENTRIES.EMPLOYEEID,
EMPLOYEENAMESURNAMEFORMAT) as subquery