order date for values with unknown day and month - sql

I'm developing a website with events from the past. For some events the whole date is known, for some the month of the year and for some only the year. Table event looks like:
id
content
date -> YYYY-MM-DD (date data type)
year -> true, if only year is known, otherwise false
monthandyear -> true if only year and month is known, otherwise false
I would like to list the contents of the table in the following order:
descending by date
if only the month and year are known (monthandyear is set to
true), the content should be listed as the last of that month
if only the year is known (year is set to true), the content should be listed as the last of that year
What is the best solution to this problem?
I'm using DQL:
SELECT p FROM App:Event p ORDER BY p.date DESC ...

You can use conditional logic. Assuming that date is a string:
order by left(date, 4),
(case when not year and not yearmonth then 1 else 2 end),
left(date, 7),
(case when not yearmonth then 1 else 2 end)
date
Edit:
If date is of type date, then:
order by year(date),
(case when not year and not yearmonth then 1 else 2 end),
month(date),
(case when not yearmonth then 1 else 2 end)
date

I solved the problem using Gordon's answer. In DQL it looks like:
$this->getEntityManager()
->createQuery(
'SELECT '
. 'p, '
. '(CASE WHEN (p.year = :yes) THEN 1 ELSE 2 END) as HIDDEN ORD1, '
. '(CASE WHEN (p.monthandyear = :yes) THEN 1 ELSE 2 END) as HIDDEN ORD2 '
. 'FROM App:Event p '
. 'ORDER BY SUBSTRING(p.dateandtime, 1, 4) DESC, ORD1 DESC, SUBSTRING(p.dateandtime, 1, 7) DESC, ORD2 DESC, p.dateandtime DESC'
)
->setParameters(array("no" => false, "yes" => true))
->getResult();

Related

SQL: create if condition for grouped variables

I have a table with 4 columns and need to create a newcolumn, which represents that if for the following year's quarter exists at least one data='colour', so for this quarter all values are changed to 'colour. How to do it?
You can use condition and get count of no for each quarter as follows:
select t.*,
case when count(case when data = 'no' then 1 end)
over (partition by year, quarter) > 0
then 'nocolour'
else data
end as new_column
from your_table t
You can use window functions:
select t.*,
min(data) over(partition by year, quarter) as new_column
from mytable t
If there is any 'no' for a given quarter, new_column takes value 'no' for all rows of the quarter. This works because string-wise, 'no' < 'yes'.
Assuming that you really mean "has data = 'yes' and the next quarter and you want to update the table, you can use:
update t
set newcolumn = (case when next_max_data = 'yes' then 'colour' else 'no colour')
from t join
(select year, quarter,
lead(max(data)) over (order by year, quarter) as next_max_data
from t
group by year, quarter
) tt
on t.year = tt.year and t.quater = tt.quarter;
If you want the the quarter a year later, you would use lead(max(data), 4) in the subquery.

Adding integers to MONTH (XX) affecting logic of CASE WHEN statement, how to go around it?

Looking to get Order ID counts per month (after user signs up for a subscription service). I'm using a CASE WHEN statement where I'm taking the transaction date, then equating that to the subscription month and adding integers for each line to get Month 0, Month 1, Month 2, etc.
Ideally looking to create a concatenated year+month column to Group By so only one query is needed to get the trickle-down order value of user cohorts months 0 through 6 post enrollment. But this first draft isn't working.
Due to some Logic errors (I believe), adding integers to the month(date) function is not being read correctly, so I'm ending up with a ton of zero's after month 0.
I have checked that there indeed is rows that aren't being pulled, when I set the month (date) condition = to a certain interger ie :
count(distinct case when month(transaction_date) = 2 then order_id end) as month_1
then the code works, so this must be due to logic with adding integers to months.
select
count(user_uuid),
count(distinct case when month(transaction_date) = month (first_subscription_date) then order_id end) as month_0,
count(distinct case when month(transaction_date) = (month (first_subscription_date) + 1) then order_id end) as month_1,
count(distinct case when month(transaction_date) = (month (first_subscription_date) + 2) then order_id end) as month_2,
count(distinct case when month(transaction_date) = (month (first_subscription_date) + 3) then order_id end) as month_3,
count(distinct case when month(transaction_date) = (month (first_subscription_date) + 4) then order_id end) as month_4,
count(distinct case when month(transaction_date) = (month (first_subscription_date) + 5) then order_id end) as month_5,
count(distinct case when month(transaction_date) = (month (first_subscription_date) + 6) then order_id end) as month_6
from sandbox.select_hbw_orders
where first_subscription_date between '2018-12-01' and '2018-12-31'
and pre_or_post_subscription = 'post'
Current results:
Count(user_uuid) month_0 month_1 month_2 month_3 month_4 month_5
34,899 11,894 0 0 0 0 0
Expected results:
Count(user_uuid) month_0 month_1 month_2 month_3 month_4 month_5
34,89 11,894 4,009 3,274 3,462 3,107 3,406
What's wrong with my logic? I'm certainly able to use filters to limit the subscription month/year, but i'm going to pull about 12 months worth of data, so I want to keep things efficient with a case when statement.

calculate YTD & Prev Year YTD

I want to calculate YTD (1st Jan 2016 to last date of a month) & Prev year YTD (1st Jan 2015 to last date of a month) for each Client.
Below is the SQL Query that i have attempted, but here i get two rows for each Client instead of 1 as I'm using 'CASE WHEN'.
My question is how can i get the result in just one row per Client instead of one row for YTD & another row for YTD-1 for each client?
SELECT [ClientName]
, (CASE WHEN YEAR([Purchase_Date]) = YEAR(GETDATE())-1 THEN (count(Activity)) end) AS 'YTD-1'
, (CASE WHEN YEAR([Purchase_Date]) = YEAR(GETDATE()) THEN (count(Activity)) end) AS 'YTD'
FROM Purchases
WHERE MONTH([Purchase_Date]) <= MONTH(GETDATE())
GROUP BY [ClientName], YEAR([Purchase_Date])
ORDER BY 1
Kindly Help!
Thanks,
Ramesh
Remove YEAR([Purchase_Date]) from the GROUP BY part.
Also, instead of:
(CASE WHEN YEAR([Purchase_Date]) = YEAR(GETDATE())-1 THEN (count(Activity)) end) AS 'YTD-1'
use:
count(CASE WHEN YEAR([Purchase_Date]) = YEAR(GETDATE())-1 THEN Activity else NULL end) AS 'YTD-1'
And the same for 'YTD' column.

Case Function in Oracle - wrong return

I have an table with these fields:
id,
quarter,
description,
id_school.
These table have this data:
ID | quarter | description
12 A 1 YEAR
12 S 1 Year
12 A DONE
I want to get the serie_school based on the below query:
select NVL(
case
WHEN quarter = 'S' AND
(UPPER(description ) LIKE 'DONE' OR
UPPER(description ) LIKE '%YEAR' OR
UPPER(description ) LIKE 'LANGUAGE') THEN -1
WHEN quarter = 'A' AND
(UPPER(description ) LIKE 'DONE' OR
UPPER(description ) LIKE '%QUARTER' OR
UPPER(description ) LIKE '%STEP' OR
UPPER(description ) LIKE 'LANGUAGE') THEN -1
WHEN quarter = 'T' THEN -1
ELSE -1
end, -1) nvl_return from test
The return of this on my query is:
ID | quarter | description | nvl_return
12 A 1 YEAR 1
12 S 1 Year 1 *- (this column has the wrong answer)*
12 A DONE -1
The answer of line 2 is wrong, because the QUARTER field is 'S' and the description field have 'year', so it needs to be -1, but in Oracle is returning 1.
Is there anyone who can help me with this?
Thanks in advance
Alexandre,
Examine your statement, where I have added "<======" to point out the various possible amounts for this column.
select NVL(
case
WHEN quarter = 'S' AND
(UPPER(description ) LIKE 'DONE' OR
UPPER(description ) LIKE '%YEAR' OR
UPPER(description ) LIKE 'LANGUAGE') THEN -1<=======
WHEN quarter = 'A' AND
(UPPER(description ) LIKE 'DONE' OR
UPPER(description ) LIKE '%QUARTER' OR
UPPER(description ) LIKE '%STEP' OR
UPPER(description ) LIKE 'LANGUAGE') THEN -1<======
WHEN quarter = 'T' THEN -1 <======
ELSE -1 <=======
end, -1 <-this will never happen) nvl_return from test
You return "-1" in every single case. "-1" is the only value returned, by the only column returned in your query.
So when you say the results are:
ID | quarter | description | nvl_return
12 A 1 YEAR 1
12 S 1 Year 1 *- (this column has the wrong answer)*
12 A DONE -1
Unfortunately, your query cannot produce the results you've stated.
Try creating a SQL fiddle, to explain the issue. SQL Fiddle

sqlite select: grouping in one line, 12 entries

I have a table with fields:
Client_ID, Date, Value
where there is an entry for each of the 12 months of a year (i.e., 12 entries for each client).
I would like to create a table with just one row per Client_ID that contains all the values from each months. Something like:
Client_ID, Date_January, Value_January, Date_February, Value_February, ........, Date_December, Value_December
Can anyone help me with the query?
This is what I'm trying to do (not working...):
select
Client_Id,
case when ((strftime('%m', Date) = '01')) then
Date as Date_January,
Value as Value_January,
else null end
case when ((strftime('%m', Date) = '01')) then
Date as Date_February,
Value as Value_February,
else null end
....
from Test_Table
where
strftime('%Y', Date) = '2013'
;
First you need to untangle your case constructs as they generate a single value. Use:
case
when ((strftime('%m', Date) = '01')) then Date
else null
end as Date_January,
case when ((strftime('%m', Date) = '01')) then Value
else null
end as Value_January,
Then, if you want one row per client, use GROUP BY ClientID.
The third issue is how to aggregate all the Date_January columns into one row. If you really know that there is exactly one row per month per client, you can use MAX() knowing that the not null value will be higher than the NULL values:
select
Client_Id,
MAX(case
when ((strftime('%m', Date) = '01')) then Date
else null
end) as Date_January,
MAX(case when ((strftime('%m', Date) = '01')) then Value
else null
end) as Value_January,
MAX(case
when ((strftime('%m', Date) = '02')) then Date
else null
end) as Date_February,
MAX(case when ((strftime('%m', Date) = '02')) then Value
else null
end) as Value_February,
....
from Test_Table
where
strftime('%Y', Date) = '2013'
group by Client_Id;