Select from a subset of data - sql

I am working on a query in MS SQL Server 2014
That basically is a lot of unions
select x, y
where a = b
union
select x, y
where a = b
union
select x, y
where a = b
It works fine, however the where clauses are identical on every select. And for ease of maintenance I was wondering if there is a better, cleaner way to do this.
I was thinking of somehow selecting the data with the where clauses first then doing all the other queries only on this data.
But im open to any ideas on how to improve this query.

;WITH Test AS
(
SELECT x, y
UNION
SELECT x, y
UNION
SELECT x, y
)
SELECT * FROM Test
WHERE a = b

You could use a sub query and take the where clause outside of it for ease of maintenance.
Just make sure you bring all the columns through in the sub query that you will need in the where clause. Eg
SELECT * FROM
(
SELECT x,y,a,b FROM table1
union
SELECT x,y,a,b FROM table2
UNION
SELECT x,y,a,b FROM table3
)subquery
WHERE a=b

Select *
From
(
select x, y
union
select x, y
union
select x, y
) MyDerivedTable
Where ...
Make sure to include the columns you need to filter in the select statement of the tables inside the derived table.

Related

Multiple Selects with Union disordered?

I have multiple selects joined by a Union as following
(
select * from x
)
UNION
(
select * from y
)
UNION
(
select * from z
)
But I'm getting disordered results on the SSMS:
z results
x results
y results
Is it possible to force results to be x, y, z?
You must provide an ORDER BY clause, otherwise no ordering is guaranteed. For example, the rows from different tables could even be interspersed.
A good option for explicit ordering, is to add a column and order by it
select *, 1 as ordering
from x
UNION
select *, 2
from y
UNION
select *, 3
from z
order by ordering;
I suspect you actually don't need UNION here (which implies DISTNCT) and you really want UNION ALL.

Count with GroupBY does not count the actual number of records, shows as 1 only

I have this simple sample that I'm working with. I have 2 records that are the same, and I'm just trying to roll these two records up so that it shows 2 as count since X and Y are exact
WITH test AS (
SELECT '11' AS X, 'BYE'AS y
UNION
SELECT '11' AS X, 'BYE' AS Y
)
SELECT x, y, COUNT(x)
FROM test
GROUP BY x,y
The problem has nothing to do with the COUNT nor the GROUP BY and everything to do with your UNION. Your CTE (test) only provides one row as a UNION query returns distinct rows and you only have one distinct row. Use UNION ALL:
WITH test AS (
SELECT '11' AS X, 'BYE'AS y
UNION ALL
SELECT '11' AS X, 'BYE' AS Y
)
SELECT x, y, COUNT(x)
FROM test
GROUP BY x,y;
Better yet, don't use that old style and use a VALUES table construct:
WITH test AS(
SELECT x,y
FROM (VALUES(11,'BYE'),
(11,'BYE'))V(x,y))
SELECT x, y, COUNT(x)
FROM test
GROUP BY x,y;

How to find minimum from a set of minimums in a query?

I have a query which looks something like :
Select min(x) from A
UNION
Select min(x) from B
UNION
Select min(x) from C
.
.
.
Select min(x) from Z
Now , i want to return the minimum of these values using a SELECT statement.
Is it possible , considering i'm using DB2 as my database?
P.S. : I'm aware that i can insert the output of the above in temp table and get the min from there. But the Insert operation is costly , since most of these have > 1BN rows.
Thanks
You could do it using a nested SELECT:
SELECT MIN(V) FROM (
Select min(x) AS V from A
UNION
Select min(x) AS V from B
UNION
Select min(x) AS V from C
.
.
.
Select min(x) AS V from Z
) t
Since you are applying an aggregate function to the values, you may as well replace UNION with UNION ALL.

How to insert UNION data into a table

I would like to use UNION on two tables in order to combine a similar field, then insert that UNION data into a different table.
Example:
Table1 has the following fields:
x
y
z
Table2 has the following fields:
x
w
v
I would like to perform UNION on x in order to insure there are no duplicate rows, then put that data in another table.
Example:
I would like MainTable to have the following fields:
x
y
z
w
v
As you can tell, all of the fields from both Table1 and Table2 exist in MainTable, but x has had UNION performed on it.
This SQL code does not work in a query, however, and is giving me Syntax Error in FROM Clause:
INSERT INTO MainTable(x)
SELECT x
FROM (Table1)
UNION
SELECT x
FROM (Table2)
Try:
INSERT INTO MainTable(x)
FROM
(
SELECT x
FROM (Table1)
UNION
SELECT x
FROM (Table2)
) as t

Different Group By Clause on same Query (Select/Where)

Can i reuse a complex select Where clause to different group by?
What i am doing:
(Select X, Count(*) From [Big where clause with many tables] Group By X)
Union All
(Select Y, Count(*) From [Big where clause with many tables] Group By Y)
How can i optmise this?
I'm using SQL Server 2008 and this will go inside a Function, but could be a stored procedure.
WITH basequery AS (Select * From [Big where clause with many tables])
SELECT X, COUNT(*) FROM basequery GROUP BY X
UNION ALL
SELECT Y, COUNT(*) FROM basequery GROUP BY Y;
CTEs were made for situations like this.
One option you could evaluate (particularly if there are relatively few x,y groups) would be to materialise the intermediate results yourself into a #table or #temp table then just SELECT from that (a #temp table would be better as you could set up better indexes than the below and it allows the select query that populates it to be parallelised but these are not available in a function)
DECLARE #T TABLE
(
X int,
Y int,
Cnt int,
UNIQUE(X,Y,Cnt), /*Cnt just included to make index covering*/
UNIQUE(Y,X,Cnt)
)
INSERT INTO #T
Select X, Y, Count(*)
From [Big where clause with many tables]
Group By X, Y
SELECT X, SUM(Cnt)
FROM #T
GROUP BY X
UNION ALL
SELECT Y, SUM(Cnt)
FROM #T
GROUP BY Y
SQL Server 2008 has introduced GROUPING SETS () which seems to be just what you are after. The UNION solution suggested by others can now easily be replaced with a single select with GROUPING SETS.
Basically, you are using it like this:
SELECT A, B, C
FROM …
WHERE …
GROUP BY GROUPING SETS ( (A), (B), (C) )
which is equivalent to
SELECT A, NULL, NULL, …
FROM …
WHERE …
GROUP BY A
UNION ALL
SELECT NULL, B, NULL, …
FROM …
WHERE …
GROUP BY B
UNION ALL
SELECT NULL, NULL, C, …
FROM …
WHERE …
GROUP BY C
So, your query might look like this:
SELECT X, Y, COUNT(*)
FROM your complex joins and filters
GROUP BY GROUPING SETS ( (X), (Y) )
Or like this:
SELECT
CASE WHEN X IS NULL THEN 'Y' ELSE 'X' END AS ObjType
CASE WHEN X IS NULL THEN Y ELSE X END AS Obj,
COUNT(*)
FROM your complex joins and filters
GROUP BY GROUPING SETS ( (X), (Y) )
The second one assumes that X cannot be NULL.
References:
GROUP BY (Transact-SQL)
GROUPING SETS Equivalents
Using GROUP BY with ROLLUP, CUBE, and GROUPING SETS
create view
CREATE VIEW SomeView
AS
Select X, Y, Count(*) AS C From [Big where clause with many tables]
then use the view:
Select X, C FROM SomeView GROUP BY X