Reason alias works in ORDER BY but not in WHERE [duplicate] - tsql

This question already has answers here:
Cannot use Alias name in WHERE clause but can in ORDER BY
(7 answers)
Closed 5 years ago.
I understand that I can't reference an alias in the WHERE clause, but why is that? Is it interpreted differently?
Something like this generates an error:
declare #myTable table
(
num numeric(5,2),
den numeric(5,2)
)
insert into #mytable
select 1, 2
union
select 1, 3
union
select 2, 3
union
select 2, 4
union
select 2, 5
union
select null, 1
select num/den as 'calc' from #myTable
where calc is not null
order by calc
But this returns rows:
declare #myTable table
(
num numeric(5,2),
den numeric(5,2)
)
insert into #mytable
select 1, 2
union
select 1, 3
union
select 2, 3
union
select 2, 4
union
select 2, 5
union
select null, 1
select num/den as 'calc' from #myTable
--where calc is not null
order by calc

As mentioned in Cannot use Alias name in WHERE clause but can in ORDER BY, it's due to the natural query processing order:
FROM
ON
OUTER
WHERE
GROUP BY
CUBE | ROLLUP
HAVING
SELECT
DISTINCT
ORDER BY
TOP

Related

How to select multi row not from table

I want select multi records for serial number, like :
select * from
(
select 11 as COMP_NO
union
select 12
union
select 13
union
select 14
union
select 15
) A
If I want to select 100 records or more, Is there a better way ?
I find another way to solve my problem, create a user-defined function:
CREATE FUNCTION [dbo].[SerialTable]
(
#BeginNo int
, #EndNo int
)
RETURNS TABLE
AS
RETURN
(
WITH MySerial(SNO, ENO)
AS(
SELECT #BeginNo AS SNO, #EndNo as ENO
UNION ALL
SELECT SNO+1, ENO
FROM MySerial
WHERE SNO<ENO
)
SELECT SNO
FROM MySerial
)
then can select 10 or more records easily
SELECT * FROM dbo.SerialTable(11, 20);
SELECT * FROM dbo.SerialTable(11, 100);

How to create a table with dates in sequence between range in Hive?

I'm trying to Create a table with column date, And I want to insert date in sequence between Range.
Here's what I have tried:
SET StartDate = '2009-01-01';
SET EndDate = '2016-06-31';
CREATE TABLE DateRangeTable(mydate DATE, qty INT);
INSERT INTO DateRangeTable VALUES (select a.Date, 0
from (
select current_date - INTERVAL (a.a + (10 * b.a) + (100 * c.a)) DAY as Date
from (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a
cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b
cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c
) AS a where a.Date between '2019-01-01' and '2016-06-30');
This is the similar one:
select date_add(t.f1, t.start_r - pe.i) as date_range from (select '2022-01-01' as f1,datediff('2022-01-07','2022-01-01') as start_r,0 as end_r) t lateral view posexplode(split(space(start_r - end_r),' ')) pe as i,s;
You do not need VALUES keyword when using INSERT ... SELECT.
Working example:
set hivevar:start_date=2009-01-01;
set hivevar:end_date=2016-06-31;
CREATE TABLE DateRangeTable(mydate DATE, qty INT);
with date_range as
(--this query generates date range
select date_add ('${hivevar:start_date}',s.i) as dt
from ( select posexplode(split(space(datediff('${hivevar:end_date}','${hivevar:start_date}')),' ')) as (i,x) ) s
)
INSERT INTO TABLE DateRangeTable
select d.dt, 0 qty
from date_range d
where d.dt between '2019-01-01' and '2016-06-30');

PostgreSQL join to denormalize a table with generate_series

I've this table:
CREATE TABLE "mytable"
( name text, count integer );
INSERT INTO mytable VALUES ('john', 4),('mark',2),('albert',3);
and I would like "denormlize" the rows in this way:
SELECT name FROM mytable JOIN generate_series(1,4) tmp(a) ON (a<=count)
so I've a number of rows for each name equals to the count column: I've 4 rows with john, 2 with mark and 3 with albert.
But i can't use the generate_series() function if I don't know the highest count (in this case 4). There is a way to do this without knowing the MAX(count) ?
select name,
generate_series(1,count)
from mytable;
Set returning functions can be used in the select list and will do a cross join with the row retrieved from the base table.
I think this is an undocumented behaviour that might go away in the future, but I'm not sure about that (I recall some discussion regarding this on the mailing list)
SQLFiddle example
DROP TABLE ztable ;
CREATE TABLE ztable (zname varchar, zvalue INTEGER NOT NULL);
INSERT INTO ztable(zname, zvalue) VALUES( 'one', 1), ( 'two', 2 ), ( 'three', 3) , ( 'four', 4 );
WITH expand AS (
WITH RECURSIVE zzz AS (
SELECT 1::integer AS rnk , t0.zname
FROM ztable t0
UNION
SELECT 1+rr.rnk , t1.zname
FROM ztable t1
JOIN zzz rr ON rr.rnk < t1.zvalue
)
SELECT zzz.zname
FROM zzz
)
SELECT x.*
FROM expand x
;

Comparing data between rows within a table

I have following table structure
table 1
ID SOURCE_ID NAME
1 1 A
2 1 B
3 2 B
4 2 C
5 2 A
i need to pick those names which are common across all SOURCE_ID , hence i expect names A and B as they are present in both the SOURCE_ID 1,2.
The following query gives me the expected output:
SELECT DISTINCT NAME
FROM TABLE1 A, TABLE1 B
WHERE A.NAME = B.NAME AND A.SOURCE_ID != B.SOURCE_ID
Now when the data in table changes to include a new record ID 6
table 1
ID SOURCE_ID NAME
1 1 A
2 1 B
3 2 B
4 2 C
5 2 A
6 3 A
The name that is common in all three SOURCE_ID(1,2,3) IS A.
My query fails to return the correct output as new records are entered.
Please provide me a query that works correctly when new records are inserted.
Have a look at something like
DECLARE #Table TABLE(
SOURCE_ID INT,
NAME VARCHAR(20)
)
INSERT INTO #Table SELECT 1,'A'
INSERT INTO #Table SELECT 1,'B'
INSERT INTO #Table SELECT 2,'B'
INSERT INTO #Table SELECT 2,'C'
INSERT INTO #Table SELECT 2,'A'
--INSERT INTO #Table SELECT 3,'A'
;WITH DistinctCount AS (
SELECT NAME,
COUNT(DISTINCT SOURCE_ID) Cnt
FROM #Table
GROUP BY NAME
)
SELECT *
FROM DistinctCount
WHERE Cnt = (SELECT COUNT(DISTINCT SOURCE_ID) FROM #Table)
With the 6th insert commented out, should return A and B, with it included, should return A

how to convert single line SQL result into multiple rows?

I am developing a T-SQL query in SSMS 2008 R2 which returns one line only. But the problem is that in this one line there are four fields which I instead want to be unique rows. For example, my output line looks like:
Col. 1 Col. 2 Col. 3 Col. 4
xxxx yyyy zzzz aaaa
Instead, I want this to look like:
Question Answer
Col. 1 xxxx
Col. 2 yyyy
Col. 3 zzzz
Col. 4 aaaa
I have tried using the UNPIVOT operator for this, but it is not doing the above. How can I achieve this?
You should be able to use UNPIVOT for this:
Here is a static pivot where you hard code in the values of the columns:
create table t1
(
col1 varchar(5),
col2 varchar(5),
col3 varchar(5),
col4 varchar(5)
)
insert into t1 values ('xxxx', 'yyyy', 'zzzz', 'aaaa')
select question, answer
FROM t1
unpivot
(
answer
for question in (col1, col2, col3, col4)
) u
drop table t1
Here is a SQL Fiddle with a demo.
but you can also use a Dynamic Unpivot:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
select #cols = stuff((select ','+quotename(C.name)
from sys.columns as C
where C.object_id = object_id('t1') and
C.name like 'Col%'
for xml path('')), 1, 1, '')
set #query = 'SELECT question, answer
from t1
unpivot
(
answer
for question in (' + #cols + ')
) p '
execute(#query)
This is from my data names but it is tested
select 'sID', sID as 'val'
from [CSdemo01].[dbo].[docSVsys]
where sID = 247
union
select 'sParID', sParID as 'val'
from [CSdemo01].[dbo].[docSVsys]
where sID = 247 ;
But UNPIVOT should work
UNION-ing together your four questions would look like:
SELECT 'column1' AS Question, MAX(column1) AS Answer UNION
SELECT 'column2' , MAX(column2) UNION
SELECT 'column3' , MAX(column3) UNION
SELECT 'column4' , MAX(column4)
(obv just using the MAX as an example)