This query:
SELECT CID, count(*) as NumOccurences
FROM Violations
WHERE DateOfViolation BETWEEN (dateadd(day, -30, getdate())) AND getdate()
GROUP BY CID
ORDER BY count(*) DESC;
gives the following result:
CID NumOccurences
1921 5
1042 5
1472 5
1543 5
2084 5
2422 5
NumOccurences is verified to be correct. Since CID exists in another tables, I want to tie CID to its intersection, a column in said other table Placement[CID,Intersection,...], and display that instead.
My desired output is:
Intersection NumOccurences
Elston and Charles 5
Diservey and Pkwy 5
Grand and Chicago 5
...
...
I tried this:
SELECT Intersection, count(DateOfViolation) as NumOccurences
FROM Violations
inner join Placement on Violations.CID = Placement.CID
WHERE DateOfViolation BETWEEN (dateadd(day, -30, getdate())) AND getdate()
GROUP BY Intersection
ORDER BY count(*) DESC;
but get this result (not correct):
Intersection NumOccurences
CALIFORNIA AND DIVERSEY 90
BELMONT AND KEDZIE 83
KOSTNER AND NORTH 82
STONEY ISLAND AND 79TH 78
RIDGE AND CLARK 60
ROOSEVELT AND HALSTED 60
ROOSEVELT AND KOSTNER 60
In fact, I've got no idea what my attempt query is even returning or where it's coming from.
EDIT
Running the query
SELECT CID, count(*) as num
from Placement
where Intersection = 'BELMONT AND KEDZIE'
group by Intersection, Address, CID
order by Intersection, Address, CID
yeilds
CID num
1372 1
1371 1
1373 1
I think you could do something like this:
SELECT
MIN(Placement.Intersection) AS Intersection,
COUNT(DISTINCT Violation.VID /* Violation ID? */) AS NumOccurences
FROM Violations INNER JOIN Placement ON Violations.CID = Placement.CID
WHERE DateOfViolation
BETWEEN cast(dateadd(day, -30, getdate()) as date) AND cast(getdate() as date)
GROUP BY Violations.CID
ORDER BY NumOccurences DESC;
Also be careful with that date range. I'm not sure whether you're dealing with date or datetime.
You might also try:
SELECT
(
SELECT MIN(Intersection) FROM Placement
WHERE Placement.CID = Violations.CID
) AS Intersection,
COUNT(*) AS NumOccurences
FROM Violations
WHERE DateOfViolation
BETWEEN cast(dateadd(day, -30, getdate()) as date) AND cast(getdate() as
GROUP BY CID
ORDER BY NumOccurences DESC;
You may not even need the MIN() in that second one.
There would have to be a one-to-one relationship between CIDs and Intersections for you to get the result you are after.
83 is actually a prime number, which would suggest that not only are there multiple entries for the BELMONT and KEDZIE intersection in the Placement table, but also that there is more than one CID corresponding to that intersection. The same may be true for other intersections
Try this:
SELECT Intersection, CID, count(*) as num
from Placement
-- where Intersection = 'BELMONT AND KEDZIE'
group by Intersection, CID
order by Intersection, CID
That will show you how many of each (intersection, CID) combination in your Placement table (uncomment the where clause to look at 'Belmont and Kenzie' specifically). Then re-ask yourself what you're trying to do.
Related
I have a table that contains Transactions of Customers.
I should Find Customers That had have at least 2 transaction with amount>20000 in Three consecutive days each month.
For example , Today is 2022/03/12 , I should Gather Data Of Transactions From 2022/02/13 To 2022/03/12, Then check These Data and See If a Customer had at least 2 Transaction With Amount>=20000 in Three consecutive days.
For Example, Consider Below Table:
Id
CustomerId
Transactiondate
Amount
1
1
2022-01-01
50000
2
2
2022_02_01
20000
3
3
2022_03_05
30000
4
3
2022_03_07
40000
5
2
2022_03_07
20000
6
4
2022_03_07
30000
7
4
2022_03_07
30000
The Out Put Should be : CustomerId =3 and CustomerId=4
I write query that Find Customer For Special day , but i don't know how to find these customers in one month with out using loop.
the query for special day is:
With cte (select customerid, amount, TransactionDate,Dateadd(day,-2,TransactionDate) as PrevDate
From Transaction
Where TransactionDate=2022-03-12)
Select CustomerId,Count(*)
From Cte
Where
TransactionDate>=Prevdate and TransactionDate<=TransactionDate
And Amount>=20000
Group By CustomerId
Having count(*)>=2
Hi there are many options how to achieve this.
I think that easies (from perfomance maybe not) is using LAG function:
WITH lagged_days AS (
SELECT
ISNULL(LAG(Transactiondate) OVER(PARTITION BY CustomerID ORDER BY id),
LEAD(Transactiondate) OVER(PARTITION BY CustomerID ORDER BY id)) lagged_dt
,*
FROM Transaction
), valid_cust_base as (
SELECT
*
FROM lagged_days
WHERE DATEPART(MONTH, lagged) = DATEPART(MONTH, Transactiondate)
AND datediff(day, Transactiondate, lagged_dt) <= 3
AND Amount >= 20000
)
SELECT
CustomerID
FROM valid_cust_base
GROUP BY CustomerID
HAVING COUNT(*) >= 2
First I have created lagged TransactionDate over customer (I assume that id is incremental). Then I have Selected only transactions within one month, with amount >= 20000 and where date difference between transaction is less then 4 days. Then just select customers who had more than 1 transaction.
In LAG First value is always missing per Customer missing, but you still need to be able say: 1st and 2nd transaction are within 3 days. Thats why I am replacing first NULL value with LEAD. It doesn't matter if you use:
ISNULL(LAG(Transactiondate) OVER(PARTITION BY CustomerID ORDER BY id),
LEAD(Transactiondate) OVER(PARTITION BY CustomerID ORDER BY id)) lagged_dt
OR
ISNULL(LEAD(Transactiondate) OVER(PARTITION BY CustomerID ORDER BY id),
LAG(Transactiondate) OVER(PARTITION BY CustomerID ORDER BY id)) lagged_dt
The main goal is to have for each transaction closest TransactionDate.
I'm writing a SQL query using a table. My requirement is that I need to generate two logical columns from one physical column with certain conditions. In SQL how to generate two logical columns in final result set?
I have so far tried using sub-queries to derive those logical columns. But that sub-query returns error when incorporate it as a column in main query.
Overall there are other tables which will be joined using SQL JOIN to derive respective columns.
Columns:
CarrierName NVARCHAR(10)
MonthDate DATETIME
Stage INT
Scenario:
In my SQL Server table there is a column called Stage of type int that contains values like 1, 2, 3, 4.
Now, I have two date criteria to apply on above column to derive two logical columns in final result set.
Criteria #1:
Get carriers from past 12 months and priors to past month end date and value of "CurrentStage" should be less than and derive "PriorStage"
Example:
Current month is: March 2019 (2019-03-25) or any given date
Past latest month end date would be: 2019-02-28
12 months prior to above past latest month would be:
From 2018-02-01 To 2019-01-31
Criteria #2:
Get Carriers from past latest month end date and derive "CurrentStage"
While writing two independent SQL SELECT statements I get my desired results.
My challenge is when I think them to integrate in one select statement.
I get this error:
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression
Code:
DECLARE #DATE DATETIME
SET #DATE = '2018-08-25';
--QUERY 1 - RECORDS WITH PREVIOUS MONTH END DATE
SELECT
T1.CarrierName AS 'Carrier_Number',
T1.Stage AS 'Monitoring_Stage–Current'
FROM
table1 T1
WHERE
T1.Stage IS NOT NULL AND
CONVERT(DATE, T1.MonthDate) = CONVERT(DATE, DATEADD(D, -(DAY(#DATE)), #DATE))
--QUERY 2 - RECORDS FROM PAST 12 MONTHS PRIOR PREVIOUS MONTH END DATE
SELECT
T2.CarrierName,
T2.Stage AS 'Monitoring_Stage–Prior'
FROM
table2 T2
WHERE
T2.Stage IS NOT NULL AND
CONVERT(DATE, T2.MonthDate) BETWEEN CONVERT(DATE, DATEADD(M, -12, DATEADD(D, -(DAY(#DATE)), #DATE)))
AND CONVERT(DATE, DATEADD(D, -(DAY(#DATE) + (DAY(DATEADD(D, -(DAY(#DATE)), #DATE)))), #DATE))
AND T2.Stage) > (SELECT DISTINCT MAX(m.Stage AS INT))
FROM table1 m
WHERE CONVERT(DATE, m.MonthDate) = CONVERT(DATE, DATEADD(D, -(DAY(#DATE)), #DATE))
AND T2.CarrierName = m.CarrierName)
My final expected result set should contain below columns.
Where CurrentStage value is less than PriorStage value.
Expected Results
CarrierName | CurrentStage | PriorStage
--------------+--------------+-------------
C11122 | 1 | 2
C32233 | 3 | 4
Actual Result
I am looking for alternatives. I.e. CTE, Union, temp table etc.
Something like:
SELECT
CarrierName,
Query 1 Result As 'CurrentStage',
Query 2 Result As 'PrioreStage'
FROM
table1
To improve this post, I am adding my response here. My resolution below for this posted question is still under evaluation hence not posting it as my final answer. But it really brought a light to my effort.
RESOLUTION:
SELECT
DISTINCT M.CarrierName, A.[CurrentStage], B.[PriorStage]
FROM
--QUERY 1 - RECORDS WITH CURRENT MONTH END DATE
(SELECT M.CarrierName, M.CarrierID
, Stage AS 'CurrentStage'
FROM table1 M
WHERE M.Stage IS NOT NULL AND
CONVERT(date, M.MonthDate) = CONVERT(date, DATEADD(D,-(DAY(#DATE)), #DATE))
)
A **inner join**
(
--QUERY 2 - RECORDS FROM PAST 12 MONTHS PRIOR CURRENT MONTH END DATE
SELECT M2.CarrierName, M2.CarrierID
, Stage AS 'PriorStage'
FROM table1 M2
WHERE M2.Stage IS NOT NULL AND
CONVERT(date, M2.MonthDate) BETWEEN CONVERT(date, DATEADD(M, -12, DATEADD(D,-(DAY(#DATE)), #DATE)))
AND CONVERT(date, DATEADD(D,-(DAY(#DATE)+(DAY(DATEADD(D,-(DAY(#DATE)), #DATE)))), #DATE))
AND M2.Stage > (SELECT DISTINCT max(m.Stage)
FROM table1 m
WHERE CONVERT(date, m.MonthDate) = CONVERT(date, DATEADD(D,-(DAY(#DATE)), #DATE)) AND
M2.CarrierName = m.CarrierName
)
) B on b.Carrier_Number = a.Carrier_Number
INNER JOIN table1 M ON A.CarrierID = M.CarrierID AND B.CarrierID = M.CarrierID
I am editing this to clarify my question.
Let's say I have a table that holds patient information. I need to find new patients for this year, and the date of their prescription first prescription when they were considered new. Anytime there is a six month gap they are considered a new patient.
How do I accomplish this using SQL. I can do this in Java and any other imperative language easily enough, but I am having problems doing this in SQL. I need this script to be run in Crystal by non-SQL users
Table:
Patient ID Prescription Date
-----------------------------------------
1 12/31/16
1 03/13/17
2 10/10/16
2 05/11/17
2 06/11/17
3 01/01/17
3 04/20/17
4 01/31/16
4 01/01/17
4 07/02/17
So Patients 2 and 4 are considered new patients. Patient 4 is considered a new patient twice, so I need dates for each time patient 4 was considered new 1/1/17 and 7/2/17. Patients 1 and 3 are not considered new this year.
So far I have the code below which tells me if they are new this year, but not if they had another six month gap this year.
SELECT DISTINCT
this_year.patient_id
,this_year.date
FROM (SELECT
patient_id
,MIN(prescription_date) as date
FROM table
WHERE prescription_date BETWEEN '2017-01-01 00:00:00.000' AND '2017-
12-31 00:00:00.000'
GROUP BY [patient_id]) AS this_year
LEFT JOIN (SELECT
patient_id
,MAX(prescription_date) as date
FROM table
WHERE prescription_date BETWEEN '2016-01-01 00:00:00.000' AND '2016-
12-31 00:00:00.000'
GROUP BY [patient_id]) AS last_year
WHERE DATEDIFF(month, last_year.date, this_year.date) > 6
OR last_year.date IS NULL
Patient 2 in your example does not meet the criteria you specified ... that being said ...
You can try something like this ... untested but should be similar (assuming you can put this in a stored procedure):
WITH ordered AS
(
SELECT *, ROW_NUMBER() OVER (ORDER BY [Prescription Date]) rn
FROM table1
)
SELECT o1.[PatientID], DATEDIFF(s, o1.[Prescription Date], o2.[Prescription Date]) diff
FROM ordered o1 JOIN ordered o2
ON o1.rn + 1 = o2.rn
WHERE DATEDIFF(m, o1.[Prescription Date], o2.[Prescription Date]) > 6
Replace table1 with the name of your table.
I assume that you mean the patient has not been prescribed in the last 6 months.
SELECT DISTINCT user_id
FROM table_name
WHERE prescribed_date >= DATEADD(month, -6, GETDATE())
This gives you the list of users that have been prescribed in the last 6 months. You want the list of users that are not in this list.
SELECT DISTINCT user_id
FROM table_name
WHERE user_id NOT IN (SELECT DISTINCT user_id
FROM table_name
WHERE prescribed_date >= DATEADD(month, -6, GETDATE()))
You'll need to amend the field and table names.
I have two queries that return the mean age of customers and I am trying to combine their columns into one table, but the problem is that when I join them together with UNION it only returns one column from the first query.
SELECT AVG(C.income) AS "<50"
FROM Customer C
WHERE DATEDIFF(YEAR, C.birthDate, GETDATE()) < 50
UNION
SELECT AVG(C1.income) AS ">50"
FROM Customer C1
WHERE DATEDIFF(YEAR, C1.birthDate, GETDATE()) > 50
This returns only one column with all the data under it
<50
But I want this where I have both the columns from the two queries
<50 | > 50
What you want is conditional aggregation:
SELECT AVG(CASE
WHEN DATEDIFF(YEAR, C.birthDate, GETDATE()) < 50 THEN C.income
END) AS "<50",
AVG(CASE
WHEN DATEDIFF(YEAR, C.birthDate, GETDATE()) > 50 THEN C.income
END) AS ">50"
FROM Customer C
This will return a single row with two columns: one for <50 and another one for >50 customers.
Note: ELSE is omitted from CASE expressions. If the WHEN predicate evaluates to false, then CASE returns NULL and thus the corresponding row does not participate in AVG calculation (credit goes to #Samrat Alamgir).
I think this will produce the output what is you wanted:
SELECT a.*, b.*
FROM
(
SELECT AVG(C.income) AS "<50"
FROM Customer C
WHERE DATEDIFF(YEAR, C.birthDate, GETDATE()) < 50
) AS a,
(
SELECT AVG(C1.income) AS ">50"
FROM Customer C1
WHERE DATEDIFF(YEAR, C1.birthDate, GETDATE()) > 50
) AS b
I'm new to MSSQL and finding an elegant way to do with the followings.
I have a table called Order and the details are as follows.
orderID orderTime quantity total
*****************************************************************
1 4/1/2013 06:00:00 AM 3 300
2 4/1/2013 09:00:00 AM 1 100
3 4/2/2013 07:33:00 PM 2 265
4 4/3/2013 04:15:00 PM 1 65
*****************************************************************
Is it possible to give out the following output?
orderDate total
*******************
4/1/2013 400
4/3/2013 65
I tried to convert the orderTime into string and further group it but somehow I failed. I'm still working hard to find a way to achieve it.
I'm using SQL Server 2008.
Sure - you can convert the orderTime to a date datatype and group by that. Your output seems to indicate you want a SUM rather than MIn/MAX, but you can adjust w/ the appropriate aggregation:
select
convert(date, orderTime) as 'orderDate',
sum(total) as 'total',
min(total) as 'Min',
max(total) as 'Max'
from Order
group by convert(date, orderTime)
order by convert(date, orderTime)
You can convert the orderTime to the Date data type:
SELECT orderDate = CONVERT(Date, orderTime)
, total = SUM(total)
FROM dbo.Order (NOLOCK)
GROUP BY CONVERT(Date, orderTime)
ORDER BY orderDate;
This will return an output of:
orderDate total
*******************
4/1/2013 400
4/2/2013 265
4/3/2013 65
It depends on the data type of orderTime. You can convert it to a date field (with no time):
SELECT CAST(orderTime AS DATE), SUM(total)
FROM Table
GROUP by CAST(orderTime AS DATE);
--dmg