I'm using postgre sql and I have a problem with where clause.
What I wanted to do was:
compare each month's data to that of previous month
select location where august to july ratio was lower than 0.7
Below is my code. I used cast as decimal because without that the result was just integers (either 0 or 1).
If I run the query, it does not return any results. It doesn't say error, but that there is no data where august < 0.7 (But there is! I checked in the original table without the where clause)
SELECT location
, round(cast(june as decimal)/may, 3) as june
, round(cast(july as decimal)/june, 3) as july
, round(cast(august as decimal)/july, 3) as august
FROM per_country
WHERE august < 0.7
Can you tell me what is wrong with my code? Thank you in advance
You cannot reuse an alias defined in the select clause in the where clause. You need to repeat the expression, or use a derived table (subquery, cte):
SELECT location
, round(june::numeric/may, 3) as june
, round(july::numeric/june, 3) as july
, round(august::numeric/july, 3) as august
FROM per_country
WHERE august::numeric/july < 0.7
Note that your existing query indicates of a bad design. You should not be storing each month in a separate table, for many reasons (scalability, efficiency, maintainability, ...). Instead, you should have each month on a separate row.
Related
I have two years worth of data that I'm summing up for instance
Date | Ingredient_cost_Amount| Cost_Share_amount |
I'm looking at two years worth of data for 2012 and 2013,
I want to roll up all the totals so I have only two rows, one row for 2012 and one row for 2013. How do I write a SQL statement that will look at the dates but display only the 4 digit year vs 8 digit daily date. I suspect the sum piece of it will be taken care of by summing those columns withe calculations, so I'm really looking for help in how to tranpose a daily date to a 4 digit year.
Help is greatly appreciated.
select DATEPART(year,[Date]) [Year]
, sum(Ingredient_cost_Amount) Total
from #table
group by DATEPART(year,[Date])
Define a range/grouping table.
Something similar to the following should work in most RDBMSs:
SELECT Grouping.id, SUM(Ingredient.ingredient_cost_amount) AS Ingredient_Cost_Amount,
SUM(Ingredient.cost_share_amount) AS Cost_Share_Amount
FROM (VALUES (2013, DATE('2013-01-01'), DATE('2014-01-01')),
(2012, DATE('2012-01-01'), DATE('2013-01-01'))) Grouping(id, gStart, gEnd)
JOIN Ingredient
ON Ingredient.date >= Grouping.gStart
AND Ingredient.date < Grouping.gEnd
GROUP BY Grouping.id
(DATE() and related conversion functions are heavily DB dependent. Some RDBMSs don't support using VALUES this way, although there are other ways to create the virtual grouping table)
See this blog post for why I used an exclusive upper bound for the range.
Using a range table this way will potentially allow the db to use indices to help with the aggregation. How much this helps depends on a bunch of other factors, like the specific RDBMS used.
I have a couple of tables in PowerPivot:
A Stock table - WKRelStrength whose fields are:
Ticker, Date, StockvsMarket% (values are percentages), RS+- (values can be 0 or 1)
A Calendar Table - Cal with a Date field.
There is a many to one relationship between the tables.
I am trying to aggregate RS+-against each row for dates between 3 months ago to the date for that row - i.e a 3 month to date sum. I have tried numerous calculations but the best I can return is an circular reference error. Here is my formula:
=calculate(sum([RS+-]),DATESINPERIOD(Cal[Date],LASTDATE(Cal[Date]),-3,Month))
Here is the xlsx file.
I couldn't download the file but what you are after is what Rob Collie calls the 'Greatest Formula in the World' (GFITW). This is untested but try:
= CALCULATE (
SUM ( WKRelStrength[RS+-] ),
FILTER (
ALL ( Cal ),
Cal[Date] <= MAX ( Cal[Date] )
&& Cal[Date]
>= MAX ( Cal[Date] ) - 90
) )
Note, this will give you the previous 90 days which is approx 3 months, getting exactly the prior 3 calendar months may be possible but arguably is less optimal as you are going to be comparing slightly different lengths of time (personal choice I guess).
Also, this will behave 'strangely' if you have a total in that it will use the last date in your selection.
First of all, the formula that you are using is designed to work as a Measure. This may not work well for a Calculated Column. Secondly, it is better to do such aggregations as a Measure level, than at individual records.
Then again, I do not fully understand your situation, but if it is absolutely important for you to do this at a Record level, you may want to use the "Earlier" Function.
If you want to filter a function, based on a value in the correspontinf row, you just have to wrap your Column name with the Earlier Function. Try changing the LastDate to Earlier in your formula.
How can i check if an date value equals a date within the summer period.
I'd expect it to be something like:
SELECT Row WHERE Orderdate BETWEEN '01/01/%' AND '31/08/%'
However i'm not allowed to use wildcards in a BETWEEN Clause, right?
/edit
That works, thanks both u guys! i'm sorry i can only pick one correct answer.
i'm not allowed to use wildcards in a BETWEEN, right?
No but you could do this:
SELECT Row WHERE MONTH(Orderdate) BETWEEN 1 AND 8
Note that adding an index on MONTH(Orderdate) will significantly speed up this query since otherwise it will have to do an INDEX SCAN or TABLE SCAN.
You want the "summer" (undefined) period. Most SQL databases would allow you to do:
WHERE month(Orderdate) in (6, 7, 8)
Otherwise, you can use extract(month from OrderDate) in (6, 7, 8)).
This assumes that the month period is defined as June, July, and August. And, there are many other database-specific solutions.
I've got a SQL statement (SQL Server Management Studio) that I'm passing data into a where-statement into via a dashboard software. The users can select the year (2013 or now 2014) and also the month (which gets passes as a numeric value - so December = 12). I need to adjust the statement to where I get the last 3 months from the year/month they select. Before, b/c the SQL statement was only dealing with 2013 data, it was just the following:
YEAR(Main.ActivityDate) = '#Request.parmYear~'
AND (Month(Main.ActivityDate) Between ('#Request.parmMonth~'-2) and '#Request.parmMonth~')
Normally, parmYear = 2013 and then whatever month they select, it will grab 2 months prior through the current month.
Now, b/c it's January 2014, I need to to grab January 2014 + December 2013 + November 2013. I'm wondering how to adjust the statement to make this happen dynamically.
Thoughts?
I do not have a running SQL Server instance to test this solution but I would suggest constructing a date and using the built in functions to calculate the previous date as those already take into consideration the multiple years etc.
Declare #requestDate date = DATEFROMPARTS('#Request.parmYear', '#Request.parmMonth', 1);
...
AND Main.ActivityDate between #requestDate AND DATEADD(month, -2, #requestDate )
See this for more details.
I had a similar problem some time ago. My solution was something like this:
WHERE YEAR(Main.ActivityDate)*12 + YEAR(Month(Main.ActivityDate))
BETWEEN '#Request.parmYear~'*12+'#Request.parmMonth~'-2
AND '#Request.parmYear~'*12+'#Request.parmMonth~'
You could improve this solution sending one parameter as the result of '#Request.parmYear~'*12+'#Request.parmMonth~'.
There are two solutions for this.
Modify your current where statement and add a condition to check for this case.
Use DATEADD function. Present in comments and other answer(s).
Modifying your where to add Condition
Note: Minor error may exists since I need to check if January has month value of zero or 1.
Example:
WHERE
(
'#Request.parmMonth~'-2 < 1 AND
YEAR(Main.ActivityDate) = '#Request.parmYear~'-1 AND
Month(Main.ActivityDate) Between
(12+'#Request.parmMonth~'-2) AND 12
)
OR
(
YEAR(Main.ActivityDate) = '#Request.parmYear~'
AND (Month(Main.ActivityDate) Between
('#Request.parmMonth~'-2) and '#Request.parmMonth~'
)
I am wondering if it's possible (without actually parsing the given string) to get the actual range (in terms of days, minutes or seconds) that is specified when you have an SQL statement like
[select 'x'
from dual
where date between to_date('20111113152049')
and to_date('20120113152049')]
I am working on a query where I'm given a string in the form of
"between to_date(A) and to_date(B)"
and would like to get that value in days to compare to a policy we let the user set so they don't enter a date range longer than say a week.
Assuming you're looking for a theoretical answer (that is: don't take this into production) this could work:
Prerequistes:
have three tables: days_seq(day_seq), month_seq(mth_seq) and year_seq(yr_seq)
days has the numbers 1...31, month 1..12, years 2011....?
Use te following query (I used access because I don't have proper RDBMS available here, keep in mind that MS-ACCESS/JET is forgiving in the use of the Dateserial function, that is, it doesn't break when you ask the dateserial for february, 30th, 2012)
SELECT Max(DateSerial(
[year_seq]![yr_seq]
,[month_seq]![mth_seq]
, [days_seq]![day_seq]))
-
Min(DateSerial(
[year_seq]![yr_seq]
,[month_seq]![mth_seq]
,[days_seq]![day_seq])) AS days
FROM days_seq, month_seq, year_seq
WHERE DateSerial(
[year_seq]![yr_seq]
,[month_seq]![mth_seq]
,[days_seq]![day_seq])
BETWEEN #2012-02-1# AND #2012-02-28#
The query basically produces a carthesian product of three tables which generates all possible days in months, months in a year for as many years as you have in the years table.
Bonus:
You could off-course generate a permanent Calendar table as X-Zero suggests.
table calendar([date])
INSERT INTO calendar
SELECT DISTINCT DateSerial(
[year_seq]![yr_seq]
,[month_seq]![mth_seq]
, [days_seq]![day_seq]))
FROM days_seq, month_seq, year_seq
You still have to pick your start year and your end year wisely. According to the Maya's an enddate of december 21st, 2012 will do.