Define a temporary table within an SQL "select" query - sql

I'm referring to MS Access SQL. Suppose I have a column with dates of birth of a population and the decades which these dates fall into.
Year Decade
1971 8
1953 6
1958 6
1929 3
1930 4
I want to create a query which will show how many people were born in each decade of a century.
I know it's going to be something like
SELECT (Year mod 100) \ 10 + 1 as [Decade], Count(*) as [How many people]
FROM People
GROUP BY (Year mod 100) \ 10 + 1
My problem is that there might be some decades in which no one was born from my population and I still want these to show up in my query, with a zero.
My ideal solution would be defining a table on the fly, consisting of rows {1,2,3,4…}, very much like you'd do in any programming language, say in Python decades = range(1,10), then creating the table with the counted people, and then joining these two together with a left join.
It seems not possible, but I'm a newbie to SQL and databases. Is that possible? What are other approaches?

MsAccess does not have a function like Range() that you can use. What I have done in my databases is create a table of numbers to use for cases like this.
The simplest way to create this table is by using an Excel spreadsheet to build the column of numbers (for instance, from 1 to 1,000) and then import the spreadsheet as a new table. Then make whatever adjustments are appropriate - for example, the new table should have a primary key on the numbers column, and the numbers column should probably be of a long integer data type. You could call the table [Numbers] and name the column [NumberValue] - these names are up (you could just as easily call your column [Nums] or even just [N]). But I would caution against using the name [Number] for a table or column because Number is a datatype name and MSAccess does not always play nicely with names that are SQL or VBA keywords.
Now you can use your new table with regular sql: Select * from [Numbers] where NumberValue >= 1 and NumberValue <= 10

First, create a small query to generate numbers:
Select Distinct Abs([id] Mod 10) As N
From MSysObjects;
Save it as Ten.
Then create a Cartesian (multiplying) query like this:
Select
Ten.N As Decade,
Val(Nz(T.C)) As [How many people]
From
Ten
Left Join
(Select Count(*) As C, [Year] Mod 10 As D
From People
Group By [Year] Mod 10) As T
On Ten.N = T.D
Output will be similar to:
Extended example that returns that dates of this year:
SELECT
DateSerial(Year(Date()),1,1+[Ten_0].[N]+[Ten_1].[N]*10+[Ten_2].[N]*100) AS [Date]
FROM
Ten AS Ten_0,
Ten AS Ten_1,
Ten AS Ten_2
WHERE
(((DateSerial(Year(Date()),1,1+[Ten_0].[N]+[Ten_1].[N]*10+[Ten_2].[N]*100))<=DateSerial(Year(Date()),12,31))
AND
((Ten_2.N)<4))
ORDER BY
DateSerial(Year(Date()),1,1+[Ten_0].[N]+[Ten_1].[N]*10+[Ten_2].[N]*100);

Related

Select same account numbers in a new table

Using Teradata SQL Assistant, I want to be able to pull a table a year ahead but only the ones that would match the results in the query from the year before. Here's what I am trying to do. I pulled a table that contains information where the results in a specific column equals 0 for no. I want to pull information from 1 year ahead where the results in that column equals 1 but only include the account numbers that came when I pulled the results for the year before. Like only pull the customer account numbers for the year ahead that are the same from the year before.
Explanation: I pull the one table that has 0 in the column. From that, I want to see which of those accounts became a 1 in the table from a year ahead. The table has millions of accounts and I just have my settings for 10,000 of them so I want to see of those 10,000 in the first year that did not have the product, how many of them became 1 in the second year.
Can I do this? If so, how? I have been googling and I do not think I am explaining what I am trying to do correctly in my google query so I am coming up short with results.
Thanks for clarifying. That makes it a little simpler. I would put the second year data in a subquery and filter the main table on the first year and quantity = 0. This will give you two columns one with the first year and one with the second year. If you're only looking for this information for a single product_id you will need to add this to both WHERE clauses.
SELECT TABLE_NAME.ACCOUNT_ID, TABLE_NAME.QUANTITY AS "2019" , YEAR_TWO.QUANTITY AS "2020"
FROM TABLE_NAME
LEFT JOIN
(
SELECT *
FROM TABLE
WHERE YEAR = 2020
) YEAR_TWO ON TABLE_NAME.ACCOUNT_ID = YEAR_TWO.ACCOUNT_ID
WHERE TABLE_NAME.YEAR = 2019
AND TABLE_NAME.QUANTITY = 0
If you want just the % of accounts that are no longer 0 in the second year you could try something like this (adding up all the 1s and dividing by total count)
SELECT TABLE_NAME.YEAR, SUM(YEAR_TWO.QUANTITY) / COUNT(YEAR_TWO.QUANTITY) AS PERCENTAGE_NOT_ZERO
FROM TABLE_NAME
LEFT JOIN
(
SELECT *
FROM TABLE
WHERE YEAR = 2020
) YEAR_TWO ON TABLE_NAME.ACCOUNT_ID = YEAR_TWO.ACCOUNT_ID
WHERE TABLE_NAME.YEAR = 2019
AND TABLE_NAME.QUANTITY = 0
GROUP BY TABLE_NAME.YEAR

Finding Year range in SQL (Microsoft Access)

I recently discovered an old Microsoft Access database I made for recording a list of books and ticking off which ones I've read and in what year.
At the moment, this includes a BOOKS table which has a column for 'Read' and 'Year'. The query which generates the table of results gets the year column and counts how many books were read in each year, e.g:
2010: 8
2011: 10
2012: 20
However, this means that if no books are marked as read in, for example, 2015, then 2015 is just left out of the chart completely. Ideally it would show up with a value of 0.
Is there any way of doing this? I don't mind delving into the SQL itself. So far my initial thoughts are working out the number of years from 2010 to current year (using DateDiff), and somehow iterating over those years to count the number of books read... but I don't know if that's possible in SQL.
Create a numbers table with one row for each year in your target year range. Then LEFT JOIN that table to BOOKS and do your counting ...
SELECT n.the_number, Nz(Count(b.Year), 0) AS books_read
FROM
numbers AS n
LEFT JOIN BOOKS AS b
ON n.the_number = b.Year
WHERE n.the_number BETWEEN 2010 AND Year(Date())
GROUP BY n.the_number;
Note you would not need the WHERE clause if your numbers table contains only the years you're interested in. However a numbers table can be useful in other situations where you might want a different range of numbers. So a similar WHERE clause will allow you to target a specific subset of the numbers contained in the table.

DAX formula for calculate Sum between 2 dates

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 query just the month and day of a DATE column?

I have a date of birth DATE column in a customer table with ~13 million rows. I would like to query this table to find all customers who were born on a certain month and day of that month, but any year.
Can I do this by casting the date into a char and doing a subscript query on the cast, or should I create an aditional char column, update it to hold just the month and day, or create three new integer columns to hold month, day and year, respectively?
This will be a very frequently used query criteria...
EDIT:... and the table has ~13 million rows.
Can you please provide an example of your best solution?
If it will be frequently used, consider a 'functional index'. Searching on that term at the Informix 11.70 InfoCentre produces a number of relevant hits.
You can use:
WHERE MONTH(date_col) = 12 AND DAY(date_col) = 25;
You can also play games such as:
WHERE MONTH(date_col) * 100 + DAY(date_col) = 1225;
This might be more suitable for a functional index, but isn't as clear for everyday use. You could easily write a stored procedure too:
Note that in the absence of a functional index, invoking functions on a column in the criterion means that an index is unlikely to be used.
CREATE FUNCTION mmdd(date_val DATE DEFAULT TODAY) RETURNING SMALLINT AS mmdd;
RETURN MONTH(date_val) * 100 + DAY(date_val);
END FUNCTION;
And use it as:
WHERE mmdd(date_col) = 1225;
Depending on how frequently you do this and how fast it needs to run you might think about splitting the date column into day, month and year columns. This would make search faster but cause all sorts of other problems when you want to retrieve a whole date (and also problems in validating that it is a date) - not a great idea.
Assuming speed isn't a probem I would do something like:
select *
FROM Table
WHERE Month(*DateOfBirthColumn*) = *SomeMonth* AND DAY(*DateOfBirthColumn*) = *SomeDay*
I don't have informix in front of me at the moment but I think the syntax is right.

SQL: selecting distinct substring from a field

I'm blacking out on my basic SQL and would appreciate a quick hand:
I have a SQLite table, with 2 columns: Datetime, and a string saying something like "call from 555-555-3344".
I need a simple query that will give me a count of all distinct phone numbers that called on a certain day.
If the field had contained just the number, I could have used Select Distinct on it. How do I do it if the value (phone number) is a substring in that field (though always the last 10 digits).
Assistance, as always, much appreciated.
Guy
You can use the following (I used 12 instead of 10 in order to include the separator -):
SELECT COUNT(DISTINCT SUBSTR(phone_nbr, -12))
FROM table
WHERE call_dt = :call_dt;