I'm working on a project that requires many INTERSECTions and uses a pretty large database, so I'd love to be able to apply TOP to my queries to make things not-so-slow.
Problem is, I know you can do something like (pseudocode-y but I hope it's understandable):
(SELECT TOP 50 * FROM A) INTERSECT (SELECT TOP 50 * FROM B); GO
BUT
can you do something along these lines in some way?
SELECT TOP 50 (SELECT * FROM A INTERSECT SELECT * FROM B); GO
You can write it as:
SELECT TOP 50 * from (SELECT * FROM A INTERSECT SELECT * FROM B) x; GO
Related
It seems we can use a SQL statement as:
select
(
select
count(*) as c_foos
from
foos
),
(
select
count(*) as c_bars
from
bars
);
but we can't do
select
(
select
count(*) as c_foos
from
foos
),
(
select
count(*) as c_bars
from
bars
),
(
select
(c_foos / c_bars) as the_ratio
);
or
select
(
select
count(*) as c_foos
from
foos
),
(
select
count(*) as c_bars
from
bars
),
(c_foos / c_bars) as the_ratio;
Is there a way to do that showing all 3 numbers? Is there a more definite rule as to what can be done and what can't?
You can try this:
You define two CTEs in a WITH clause, so you can use your result in the main query built on two cte tables (cte_num and cte_den)
WITH recursive
cte_num AS (
SELECT count(*) as c_foos
FROM foos
),
cte_den AS (
SELECT count(*) as c_bars
FROM bars
)
SELECT
cte_num.foos,
cte_den.bars,
cte_num.foos / cte_den.bars as the_ratio
from cte_num, cte_den;
There is a small number of simple rules... but SQL seems so easy that most programmers prefer to cut to the chase, and later complain they didn't get the plot :)
You can think of a query as a description of a flow: columns in a select share inputs (defined in from), but are evaluated "in parallel", without seeing each other. Your complex example boils down to the fact, that you cannot do this:
select 1 as a, 2 as b, a + b;
fields a and b are defined as outputs from the query, but there are no inputs called a and b. All you have to do is modify the query so that a and b are inputs:
select a + b from (select 1 as a, 2 as b) as inputs
And this will work (this is, btw., the solution for your queries).
Addendum:
The confusion comes from the fact, that in most SQL 101 cases outputs are created directly from inputs (data just passes through).
This flow model is useful, because it makes things easier to reason about in more complex cases. Also, we avoid ambiguities and loops. You can think about it in the context of query like: select name as last_name, last_name as name, name || ' ' || last_name from person;
Move the conditions to the FROM clause:
select f.c_foos, b.c_bars, f.c_foos / f.c_bars
from (select count(*) as c_foos from foos
) f cross join
(select count(*) as c_bars from bars
) b;
Ironically, your first version will work in MySQL (see here). I don't actually think this is intentional. I think it is an artifact of their parser -- meaning that it happens to work but might stop working in future versions.
The simplest way is to use a CTE that returns the 2 columns:
with cte as (
select
(select count(*) from foos) as c_foos,
(select count(*) from bars) as c_bars
)
select c_foos, c_bars, (c_foos / c_bars) as the_ratio
from cte
Note that the aliases of the 2 columns must be set outside of each query and not inside (the parentheses).
Can I write something like below. But this is not giving proper output in WinSQL/Teradata
with
a (x) as ( select 1 ),
b (y) as ( select * from a )
select * from b
Do you really need to use CTEs for this particular solution when derived tables would work as well:
SELECT B.*
FROM (SELECT A.*
FROM (SELECT 1 AS Col1) A
) B;
That being said, I believe multiple CTEs are available in Teradata 14.10 or 15. I believe support for a single CTE and the WITH clause were introduced in Teradata 12 or 13.
You call the dependent 1st and then the parent
like this and it will work. Why is it like that ? Teradata likes people to play with it longer and spend more time with it, making it feel important
with
"b" (y) as ( select * from "a" ),
"a" (x) as ( select '1' )
select * from b
Currently I have UNION's between 3 different select statements giving me three rows. What I'm needing is to modify this to have the union inside the from clause so that I can generate more columns (if I understand the functionality).
Basically what is going on is that the existing framework is designed and built to have a single row of data returned to it and will require heavy modification to handle a multi-row result set (everything is getting parsed to xml before being passed to the front-end).
My biggest issue (I believe) is being able to differentiate between the three sub selects inside the primary.
Guarantees in the select
1) Each select inside the from will only produce a single row result set.
2) All result sets from inside of the from will have same column count and column names (inherent of union I believe)
For example...
I currently have
SELECT * FROM A
UNION
SELECT * FROM B
UNION
SELECT * FROM C
Doing it this way produces a three row result set.
What I'm wanting if possible is....
SELECT cost as CurrentSelectedCost, /* from first select */
cost as PreviousCost, /* from second select */
cost as NextCost /* from third select */
FROM (
SELECT * FROM A
UNION
SELECT * FROM B
UNION
SELECT * FROM C
)
Now I'm guessing that I will need to alias the different select statements that are within the from clause, but I'm having issues getting that to function. The examples that I've found on here didn't seem to address the need to have all select statements inside of from differentiated. If this has been answered on here a link will suffice no reason to re-invent the wheel (I may just not know the terminology to search for) Also the database is a DB2 instance running on an iSeries
You need to unify the columns retrieved from the three SELECT statements.
SELECT CurrentSelectedCost,
PreviousCost,
NextCost
FROM (
SELECT cost as CurrentSelectedCost, 0 as PreviousCost, 0 as NextCost FROM A
UNION
SELECT 0 as CurrentSelectedCost, cost as PreviousCost, 0 as NextCost FROM B
UNION
SELECT 0 as CurrentSelectedCost, 0 as PreviousCost, cost as NextCost FROM C
) as COSTS
SELECT (SELECT COLNAME FROM A) CurrentSelectedCost,
(SELECT COLNAME FROM B) PreviousCost,
(SELECT COLNAME FROM C) NextCost
FROM DUAL
i dont think you need a union. there does not appear to be any join condition so maybe this will do it:
SELECT A.cost as CurrentSelectedCost, /* from first select */
B.cost as PreviousCost, /* from second select */
C.cost as NextCost /* from third select */
FROM A,B,C
In my application I use SELECT TOP 12 * clause to select top 12 records from database and show it to user. In another case I have to show the same result one by one. So I use SELECT TOP 1 * clause,rest of the query is same. I used Sql row_number() function to select items one by on serially.
The problem is SELECT TOP 1 * doesn't return me same row as I get in SELECT TOP 12 *. Also the result set of SELECT TOP 12 * get changed each time I execute the query.
Can anybody explain me why the result is not get same in SELECT TOP 12 * and SELECT TOP 1 *.
FYI: here is my sql
select distinct top 1 * from(
select row_number() over ( ORDER BY Ratings desc ) as Row, * from(
SELECT vw.IsHide, vw.UpdateDate, vw.UserID, vw.UploadPath, vw.MediaUploadID, vw.Ratings, vw.Caption, vw.UserName, vw.BirthYear, vw.BirthDay, vw.BirthMonth, vw.Gender, vw.CityProvince, vw.Approved
FROM VW_Media as vw ,Users as u WITH(NOLOCk)
WHERE vw.IsHide='false' and
GenderNVID=5 and
vw.UserID=u.UserID and
vw.UserID not in(205092) and
vw.UploadTypeNVID=1106 and
vw.IsDeleted='false' and
vw.Approved = 1 and
u.HideProfile=0 and
u.StatusNVID=126 and
vw.UserID not in(Select BlockedToUserID from BlockList WITH(NOLOCk) where UserID=205092) a) totalres where row >0
Thanks in Advance
Sachin
When you use SELECT TOP, you must use also the ORDER BY clause to avoid different results every time.
For performance resons, the database is free to return the records in any order it likes if you don't specify any ordering.
So, you always have to specify in which order you want the records, if you want them in any specific order.
Up to some version of SQL Server (7 IIRC) the natural order of the table was preserved in the result if you didn't specify any ordering, but this feature was removed in later versions.
I need to generate multiple random values under SQL Server 2005 and somehow this simply wont work
with Random(Value) as
(
select rand() Value
union all
select rand() from Random
)select top 10 * from Random
Whats the preffered workaround?
have you tries something like this (found at http://weblogs.sqlteam.com ) :
CREATE VIEW vRandNumber
AS
SELECT RAND() as RandNumber
GO
create a function
CREATE FUNCTION RandNumber()
RETURNS float
AS
BEGIN
RETURN (SELECT RandNumber FROM vRandNumber)
END
GO
then you can call it in your selects as normal
Select dbo.RandNumber() , * from myTable
or from their comments:
select RAND(CAST(NEWID() AS BINARY(6))), * from myTable
I'm currently using this:
with Random(Value) as
(
select rand(checksum(newid())) Value
union all
select rand(checksum(newid())) from Random
)select top 10 * from Random
but that seems overly hackish :S
Why doesnt rand get reevaluated in the first version?