I have a table named A. it has only one record with one field. It is an integer named number.
I want to create a view that have A.number records, each are one of the numbers less than A.number.
For example:
select A.number -----> 5
the view should show 5 records 0 1 2 3 4
P.S: This is a real problem that I simplified it a lot. The real problem is like dividing a budget in a fixed period to each day.
This sounds a bit like it might be homework, so I'm wary of providing the code outright.
I can give a pointer for how to solve the question, though. You use a recursive CTE where each iteration adds one to the previous iteration. Just be sure to set the MAXRECURSION option if you'll be checking numbers > 101. You can use a scalar sub query to key the view to the original table:
WITH numbers ( n ) AS (
SELECT 0 UNION ALL
SELECT 1 + n FROM numbers WHERE n < (select number from a) -1)
SELECT n FROM numbers
OPTION ( MAXRECURSION 500) --example
If the number of your table will be < 2048 and you are on SQL Server, this will work for you:
CREATE VIEW MyView AS
SELECT number
FROM master..spt_values
WHERE type = 'p'
AND number < (SELECT value FROM yourTable)
Alternatively you could consider creating your own Numbers table with an appropriate size to suit your application if you require a higher limit, or are not on SQL Server that has this provided to you. Here is a link to a blog post on the idea of having a "Numbers table" handy.
Related
I have the following codes in SAS:
proc sql;
create table play2
as select a.anndats,a.amaskcd,count(b.amaskcd) as experience
from test1 as a, test1 as b
where a.amaskcd = b.amaskcd and intck('day', b.anndats, a.anndats)>0
group by a.amaskcd, a.ANNDATS;
quit;
The data test1 has 32 distinct obs, while this play2 only returns 22 obs. All I want to do is for each obs, count the number of appearance for the same amaskcd in history. What is the best way to solve this? Thanks.
The reason this would return 22 observations - which might not actually be 22 distinct from the 32 - is that this is a comma join, which in this case ends up being basically an inner join. For any given row a if there are no rows b which have a later anndats with the same amaskcd, then that a will not be returned.
What you want to do here is a left join, which returns all rows from a once.
create table play2
as select ...
from test1 a
left join test1 b
on a.amaskcd=b.amaskcd
where intck(...)>0
group by ...
;
I would actually write this differently, as I'm not sure the above will do exactly what you want.
create table play2
as select a.anndats, a.amaskcd,
(select count(1) from test1 b
where b.amaskcd=a.amaskcd
and b.anndats>a.anndats /* intck('day') is pointless, dates are stored as integer days */
) as experience
from test1 a
;
If your test1 isn't already grouped by amaskcd and anndats, you may need to rework this some. This kind of subquery is easier to write and more accurately reflects what you're trying to do, I suspect.
If both the anndats variables in each dataset are date type (not date time) then you can simple do an equals. Date variables in SAS are simply integers where 1 represents one day. You would not need to use the intck function to tell the days differnce, just use subtraction.
The second thing I noticed is your code looks for > 0 days returned. The intck function can return a negative value if the second value is less than the first.
I am still not sure I understand what your looking to produce in the query. It's joining two datasets using the amaskcd field as the key. Your then filtering based on anndats, only selecting records where b anndats value is less than a anndats or b.anndats < a.anndats.
I have a sql server database table containing a normalized subversion log. However, some revisions are missing. How do I get all missing revisions?
I tried
SELECT Revision + 1
FROM SvnLog
WHERE Revision + 1 NOT IN (SELECT Revision FROM SvnLog)
but that leaves out anything after the first missing revision in the case of a missing range. For example, if 100-110 are missing, it only picks up 100.
I also tried
WITH revs(rev) AS (
SELECT 0
UNION ALL
SELECT revs.rev + 1
FROM revs
WHERE revs.rev <90000
)
SELECT rev
FROM revs
WHERE rev NOT IN (SELECT Revision from SVNLog)
but the recursion in the CTE was cut off at 100 and I have thousands of revisions.
I find this problem is easier to approach using lengths of gaps in the numbers, rather than listing each one out individually. After all, doing recursion for tens of thousands or hundreds of thousands of rows is likely to be less performant than you would like.
You don't specify which version of SQL Server you are using. In SQL Server 2012, this would be most easily done using lag(). But here is a more generic version:
select (revision + 1) as gapStart, (nextrevision) - 1 as gapEnd
from (select l.revision,
(select min(l2.revision)
from SVNLog l2
where l2.revision > l.revision
) as NextRevision
from SVNLog l
) l
where nextrevision <> revision + 1;
For performance, you want an index on SVNLog(Revision).
This also misses initial gaps and certain other details. Before filling those in, though, I don't know if this format meets your needs.
By the way, if you want to know if there are any gaps at all, you can just do:
select (max(revision) - min(revision) + 1) - count(distinct revision)
from SVNLog l;
If there are no gaps, then this will return 0. Otherwise, there are gaps.
There is OPTION which control recursion dept for CTE. You can use MAXRECURSION 0 which removes limit.
WITH revs(rev) AS (
SELECT 0
UNION ALL
SELECT revs.rev + 1
FROM revs
WHERE revs.rev <90000
)
SELECT rev
FROM revs
WHERE rev NOT IN (SELECT Revision from SVNLog)
OPTION (MAXRECURSION 0);
I need to generate an array of sequential integers with a given range in order to use it in:
SELECT tbl.pk_id
FROM tbl
WHERE tbl.pk_id NOT IN (sequential array);
If you have a given range - ie a start point and an end point - of sequential integers you should just be able to use the BETWEEN keyword:
SELECT tbl.pk_id
FROM tbl
WHERE tbl.pk_id NOT BETWEEN START_INT AND END_INT
or am I misunderstanding your question..?
Because you say you've already got a number table, I would suggest this:
SELECT element
FROM series
WHERE element NOT IN (SELECT pk_id
FROM tbl)
Might possibly be more efficient than the query you've tried.
Two thoughts . . .
First, there's no standard SQL function that does that. But some systems include a non-standard function that does generates a series. In PostgreSQL, for example, you can use the generate_series() function.
select generate_series(1,100000);
1
2
3
...
100000
That function essentially returns a table; it can be used in joins.
If Informix doesn't have a function that does something similar, maybe you can write an Informix SPL function that does.
Second, you could just create a one-column table and populate it with a series of integers. This works on all platforms, and doesn't require programming. It requires only minimal maintenance. (You need to keep more integers in this table than you're using in your production table.)
create table integers (
i integer primary key
);
Use a spreadsheet or a utility program to generate a series of integers to populate it. The easiest way if you have a Unix, Linux, or Cygwin environment laying around is to use seq.
$ seq 1 5 > integers
$ cat integers
1
2
3
4
5
Informix has a free developer version you can download. Maybe you can build a compelling demo with it, and management will let you upgrade.
i'll suggest a generic solution to create a result set containing the positive integers 0 .. 2^k-1 for a given k for subsequent use as a subquery, view or materialized view.
the code below illustrates the technique for k=2.
SELECT bv0 + 2* bv1 + 4*bv2 val
FROM (
SELECT *
FROM
(
SELECT 0 bv0 FROM DUAL
UNION
SELECT 1 bv0 FROM DUAL
) bit0
CROSS JOIN (
SELECT 0 bv1 FROM DUAL
UNION
SELECT 1 bv1 FROM DUAL
) bit1
CROSS JOIN (
SELECT 0 bv2 FROM DUAL
UNION
SELECT 1 bv2 FROM DUAL
) bit2
) pow2
;
i hope that helps you with your task
best regards,
carsten
I am wondering if it's possible to use a view to get the top 5 lines from a table.
I am finding that Crystal reports doesn't seem to have anything built in to do this, or I'd do it there.
When I query the view Select * from qryTranHistory, it returns the first 5 items, but if I try to select a specific type Select * from qryTranHistory Where tID = 45 it returns nothing, since there are no tID=45 in the top 5 normally.
Is it possible to do this?
Can it be accomplished in a sub report in Crystal Reports?
It is easy to limit a report to the top 5 records. In the menu, just choose
Report --> Selection Formulas... --> Group
In the formula, enter "RecordNumber <= 5" and you are done.
You don't need to have a group field nor summary field to do the group filter. You don't need a sort order, but using top N records without a sort order doesn't usually make much sense. It might not be efficient as OMG Ponies suggested, but for small number of records it is OK.
You can reference a sproc from Crystal Reports. In the sproc, use a conditional on the parameter.
ALTER PROCEDURE dbo.Get_TOP5
(
#tID INT = NULL
)
AS
IF #tID IS NULL
BEGIN
SELECT TOP 5
FIELD1,
FIELD2
FROM qryTranHistory
END
ELSE
BEGIN
SELECT
FIELD1,
FIELD2
FROM qryTranHistory
WHERE tID =#tID
END
A simple setting can limit the records to top 5!! Here it is, if you're using .Net 1.1 (similar arrangement of options in higher frameworks too!).
Right click on the report layout > Reports > Top N/Sort Group Expert > Choose Top N in the Dropdown that asks for the type of filtering/ sorting you wish to do > Set the Value of top N (5 in your case) > Uncheck the option that includes other records.
Your report will be filtered for only the top 5 records from the Dataset.
There's another way how it could be done and that is through the Record selection formula where you limit the No. of records, as suggested by John Price in this thread.
Cheers!
Can you put the TOP in your SELECT statement instead of in the view?
SELECT TOP 5
col1,
col2,
...
FROM
qryTranHistory
WHERE
tid = 45
If your table has more then 5 rows I hope this query:
SELECT * FROM qryTranHistory
Returns more then 5 rows because you never mentioned TOP 5.
Your question doesn't make a lot of sense as I am not sure waht you are after.
You mentioned if you ran your query with WHERE tID=45, it returns nothing, what exactly do you want it to return ?
Read up on TOP in BOL:
SELECT TOP 10 Recs FROM Records WHERE...
By the way you do not want to do this in the report / a form interface, you want to do this in your db layer.
You can do Top N processing in Crystal Reports, but it's a little obscure - you have to use the group sort expert (and in order to use that, you need to have groups and summary fields inserted into the groups.)
Doing the Top N processing in the query should be more efficient, where possible.
If you have a small recordset, you can create a running total that counts the change of rows (field1), then in Section Expert in Details, tell it to supress RTotal0 (your running total variable) to > 5
I am attempting to pull ALOT of data from a fox pro database, work with it and insert it into a mysql db. It is too much to do all at once so want to do it in batches of say 10 000 records. What is the equivalent to LIMIT 5, 10 in Fox Pro SQL, would like a select statement like
select name, address from people limit 5, 10;
ie only get 10 results back, starting at the 5th. Have looked around online and they only make mention of top which is obviously not of much use.
Take a look at the RecNo() function.
FoxPro does not have direct support for a LIMIT clause. It does have "TOP nn" but that only provides the "top-most records" within a given percentage, and even that has a limitation of 32k records returned (maximum).
You might be better off dumping the data as a CSV, or if that isn't practical (due to size issues), writing a small FoxPro script that auto-generates a series of BEGIN-INSERT(x10000)-COMMIT statements that dump to a series of text files. Of course, you would need a FoxPro development environment for this, so this may not apply to your situation...
Visual FoxPro does not support LIMIT directly.
I used the following query to get over the limitation:
SELECT TOP 100 * from PEOPLE WHERE RECNO() > 1000 ORDER BY ID;
where 100 is the limit and 1000 is the offset.
It is very easy to get around LIMIT clause using TOP clause ; if you want to extract from record _start to record _finish from a file named _test, you can do :
[VFP]
** assuming _start <= _finish, if not you get a top clause error
*
_finish = MIN(RECCOUNT('_test'),_finish)
*
SELECT * FROM (SELECT TOP (_finish - _start + 1) * FROM (SELECT TOP _finish *, RECNO() AS _tempo FROM _test ORDER BY _tempo) xx ORDER BY _tempo DESC) yy ORDER BY _tempo
**
[/VFP]
I had to convert a Foxpro database to Mysql a few years ago. What I did to solve this was add an auto-incrementing id column to the Foxpro table and use that as the row reference.
So then you could do something like.
select name, address from people where id >= 5 and id <= 10;
The Foxpro sql documentation does not show anything similar to limit.
Here, adapt this to your tables. Took me like 2 mins, i do this waaaay too often.
N1 - group by whatever, and make sure you got a max(id), you can use recno() to make one, sorted correctly
N2 - Joins N1 where the ID = Max Id of N1, display the field you want from N2
Then if you want to join to other tables, put that all in brackets and give it an alias and include it in a join.
Select N1.reference, N1.OrderNoteCount, N2.notes_desc LastNote
FROM
(select reference, count(reference) OrderNoteCount, Max(notes_key) MaxNoteId
from custnote
where reference != ''
Group by reference
) N1
JOIN
(
select reference, count(reference) OrderNoteCount, notes_key, notes_desc
from custnote
where reference != ''
Group by reference, notes_key, notes_desc
) N2 ON N1.MaxNoteId = N2.notes_key
To expand on Eyvind's answer I would create a program to uses the RecNo() function to pull records within a given range, say 10,000 records.
You could then programmatically cycle through the large table in chucks of 10,000 records at a time and preform your data load into you MySQL database.
By using the RecNO() function you can be certain not to insert rows more than once, and be able to restart at a know point in the data load process. That by it's self can be very handy in the event you need to stop and restart the load process.
Depending on the number of the returned rows and if you are using .NET Framework you can offset/limit the gotten DataTable on the following way:
dataTable = dataTable.AsEnumerable().Skip(offset).Take(limit).CopyToDataTable();
Remember to add the Assembly System.Data.DataSetExtensions.