Order by on an inline view - tsql

I would like to get the top 10 data from a table which needs to be sorted in ascending order in a outer query. Below is the pseudocode of the query. What are the options other than using table valued functions?
select * from
(select top 10 tour_date
from tourtable
order by tour_date desc)
order by tour_date asc

Your query as written should work, you'd just need to alias the subquery:
select *
from (select top 10 tour_date from tourtable order by tour_date desc) t
order by tour_date asc
Another alternative, assuming SQL Server 2005+:
SELECT t.tour_date
FROM (SELECT tour_date, ROW_NUMBER() OVER(ORDER BY tour_date DESC) AS RowNum
FROM tourtable) t
WHERE t.RowNum <= 10
ORDER BY t.tour_date ASC
which could also be written with a CTE:
WITH cteRowNum AS (
SELECT tour_date, ROW_NUMBER() OVER(ORDER BY tour_date DESC) AS RowNum
FROM tourtable
)
SELECT tour_date
FROM cteRowNum
WHERE RowNum <= 10
ORDER BY tour_date ASC

Tested in a non-tsql context:
select * from (select tour_date from tourable order by tour_date desc limit 10) a order by tour_date asc

Related

Using WITH clause and INSERT statement in POSTGRESQL

There was a question asked several years ago with a similar title (Using WITH clause with INSERT statement in POSTGRESQL), but I need to figure out a more complicated situation.
I've used the example from POSTGRESQL for using a "With" statement (https://www.postgresql.org/docs/current/queries-with.html). Let's say I made a pre-computed table and wanted to insert the output from the query into it (top_region, total_sales, product_units, and product_sales), how would I do that?
Precomputed table
INSERT INTO top (top_region, total_sales, product_units, product_sales)
select top_region, total_sales, product_units, product_sales
from #not sure here
WITH regional_sales AS (
SELECT region, SUM(amount) AS total_sales
FROM orders
GROUP BY region
), top_regions AS (
SELECT region
FROM regional_sales
WHERE total_sales > (SELECT SUM(total_sales)/10 FROM regional_sales)
)
SELECT region,
product,
SUM(quantity) AS product_units,
SUM(amount) AS product_sales
FROM orders
WHERE region IN (SELECT region FROM top_regions)
GROUP BY region, product;
My query
WITH sales_data AS (
SELECT s.customer_id, s.product_id, s.quantity, pr.list_price, pr.category_id, c.state_id
FROM order_products s
INNER JOIN Products pr ON (s.product_id = pr.product_id)
INNER JOIN Customer c ON (s.customer_id = c.customer_id)
),
t_20cat AS (
SELECT category_id, ROW_NUMBER() OVER (ORDER BY SUM(list_price*quantity) DESC) AS "rank", SUM(list_price*quantity) AS total_sales FROM sales_data
GROUP BY category_id ORDER BY total_sales DESC LIMIT 20
),
t_20cust AS (
SELECT customer_id, ROW_NUMBER() OVER (ORDER BY SUM(list_price*quantity) DESC) AS "rank", SUM(list_price*quantity) AS total_sales FROM sales_data
GROUP BY customer_id ORDER BY total_sales DESC LIMIT 20
),
t_20cc AS (
SELECT customer_id, t_20cust.rank as customer_rank, category_id, t_20cat.rank as category_rank FROM t_20cat, t_20cust
)
SELECT t_20cc.*, COALESCE(SUM(sales_data.quantity), 0) AS quantity_sold, COALESCE(SUM(sales_data.list_price*sales_data.quantity), 0) AS dollar_value
FROM t_20cc
LEFT JOIN sales_data ON (
t_20cc.customer_id = sales_data.customer_id AND t_20cc.category_id = sales_data.category_id
)
GROUP BY t_20cc.customer_id, t_20cc.customer_rank, t_20cc.category_id, t_20cc.category_rank
INSERT INTO top_20(customer_id, customer_rank, category_id, category_rank
select category_id, category_rank, category_id, category_rank
from t_20cc
)
Move the other SELECT query into its own CTE (region_summary), then reference that in the INSERT statement's SELECT ... FROM clause:
WITH regional_sales AS (
SELECT
region,
SUM(amount) AS total_sales
FROM
orders
GROUP BY
region
),
top_regions AS (
SELECT
region
FROM
regional_sales
WHERE
total_sales > ( SELECT SUM( total_sales ) / 10 FROM regional_sales )
),
region_summary AS (
SELECT
region,
product,
SUM(quantity) AS product_units,
SUM(amount) AS product_sales
FROM
orders
WHERE
region IN ( SELECT region FROM top_regions )
GROUP BY
region,
product
)
INSERT INTO top ( top_region, total_sales, product_units, product_sales )
SELECT
region AS top_region,
product AS total_sales,
product_units,
product_sales
FROM
region_summary;

Postgresql - Syntax error - while using with table_name as

Not sure what needs to be done , i am using pgadmin3 but regardless of the GUI i keep getting the same error .
Below is my query :
with base_table as
(select row_number() over (partition by p.customer_id order by p.payment_date ) as early_order,
row_number() over (partition by p.customer_id order by p.payment_date desc) as last_order
from payment p)
Syntax error at the end of input
I have even tried adding a semicolon at the end, doesnt work :
with base_table as
(select row_number() over (partition by p.customer_id order by p.payment_date ) as early_order,
row_number() over (partition by p.customer_id order by p.payment_date desc) as last_order
from payment p);
Syntax error near ";"
The inner query (which is below) works just fine :
select row_number() over (partition by p.customer_id order by p.payment_date ) as early_order,
row_number() over (partition by p.customer_id order by p.payment_date desc) as last_order
from payment p
Its only when i use with table_name as , that the errors start to show up.
You need to add main select:
with base_table as (
select row_number() over(partition by p.customer_id order by p.payment_date) as early_order,
row_number() over(partition by p.customer_id order by p.payment_date desc) as last_order
from payment p)
SELECT *
FROM base_table

How to use a Table type in query

I have 9000 row in News table and use this code for selecting 20 from it:
Select *
From (
Select *, ROW_NUMBER() OVER (ORDER BY DateSend DESC) AS Num
From News
Where SubjectID in(Select MenuSubject.SubjectID
From MenuSubject inner join Menu on MenuSubject.MenuID = Menu.MenuID)
) as myTable
where myTable.Num BETWEEN 100 and 120
But time is 28 second spent reading! Also, I test this query with out join table and get result at 1 second.
So, I want use Table type for select join table and use this in query. I made new Table type using the following code:
DECLARE #MyTable2 IntListTable
Insert Into #MyTable2
Select MenuSubject.SubjectID
From MenuSubject inner join Menu on MenuSubject.MenuID = Menu.MenuID
Select *
From (
Select *, ROW_NUMBER() OVER (ORDER BY DateSend DESC) AS Num
From News
Where SubjectID in #MyTable2
) as myTable
where myTable.Num BETWEEN 100 and 120
But get Error in
SubjectID in #MyTable2
Error:
Incorrect syntax near '#MyTable2'.
Edit:
I test my code with:
Select myTable.Title
or use this code instead join table:
Where SubjectID in(13,14,20,21,25,24,26,24,28,29,30,54,55,60,47,98,99,65,14,20,33,666,987,254)
get result at 1 second.
but use this code in query:
Select myTable.MoreText
time is 28 second spent reading!. why!?
Try this,
Select x.Num
From (
Select *, ROW_NUMBER() OVER (ORDER BY DateSend DESC) AS Num
From News
Where SubjectID in(Select MenuSubject.SubjectID
From MenuSubject inner join Menu on MenuSubject.MenuID = Menu.MenuID)
) x
where x.Num <21
WITH myTempTable as (Select MenuSubject.SubjectID
From MenuSubject inner join Menu on MenuSubject.MenuID = Menu.MenuID)
Select *
From (
Select *, ROW_NUMBER() OVER (ORDER BY DateSend DESC) AS Num
From News
Where SubjectID in (SELECT SubjectID FROM myTempTable)
) as myTable
where myTable.Num BETWEEN 100 and 120
You can try above query.
There is absolutely no need for a User-Defined Table Type in this query. It adds work but no actual benefit.
The problem is most likely the fact that you are using an IN list as those translate out to be an OR condition for each of the values. But an IN list isn't needed either.
This query can actually be simplified by rethinking it in terms of an INNER JOIN, which should be better as it will allow the Query Optimizer to do its job.
SELECT *
FROM (
SELECT nw.*, ROW_NUMBER() OVER (ORDER BY DateSend DESC) AS [Num]
FROM News nw
INNER JOIN (
MenuSubject
INNER JOIN Menu
ON MenuSubject.MenuID = Menu.MenuID
) ON MenuSubject.SubjectID = nw.SubjectID
) AS myTable
WHERE myTable.Num BETWEEN 100 AND 120;
One final simplification that can be made, though I doubt it is needed here since 9000 rows is almost no data at all, is to first dump the results to a local temporary table and then use that in the INNER JOIN:
CREATE TABLE #Subjects
(
SubjectID INT NOT NULL -- PRIMARY KEY -- test with and without PK to see if it helps
);
INSERT INTO #Subjects (SubjectID)
SELECT MenuSubject.SubjectID
FROM MenuSubject
INNER JOIN Menu
ON Menu.MenuID = MenuSubject.MenuID;
SELECT *
FROM (
SELECT nw.*, ROW_NUMBER() OVER (ORDER BY DateSend DESC) AS [Num]
FROM News nw
INNER JOIN #Subjects sub
ON sub.SubjectID = nw.SubjectID
) AS myTable
WHERE myTable.Num BETWEEN 100 AND 120;

SQL Server SUM() for DISTINCT records

I have a field called "Users", and I want to run SUM() on that field that returns the sum of all DISTINCT records. I thought that this would work:
SELECT SUM(DISTINCT table_name.users)
FROM table_name
But it's not selecting DISTINCT records, it's just running as if I had run SUM(table_name.users).
What would I have to do to add only the distinct records from this field?
Use count()
SELECT count(DISTINCT table_name.users)
FROM table_name
SQLFiddle demo
This code seems to indicate sum(distinct ) and sum() return different values.
with t as (
select 1 as a
union all
select '1'
union all
select '2'
union all
select '4'
)
select sum(distinct a) as DistinctSum, sum(a) as allSum, count(distinct a) as distinctCount, count(a) as allCount from t
Do you actually have non-distinct values?
select count(1), users
from table_name
group by users
having count(1) > 1
If not, the sums will be identical.
You can see for yourself that distinct works with the following example. Here I create a subquery with duplicate values, then I do a sum distinct on those values.
select DistinctSum=sum(distinct x), RegularSum=Sum(x)
from
(
select x=1
union All
select 1
union All
select 2
union All
select 2
) x
You can see that the distinct sum column returns 3 and the regular sum returns 6 in this example.
You can use a sub-query:
select sum(users)
from (select distinct users from table_name);
SUM(DISTINCTROW table_name.something)
It worked for me (innodb).
Description - "DISTINCTROW omits data based on entire duplicate records, not just duplicate fields." http://office.microsoft.com/en-001/access-help/all-distinct-distinctrow-top-predicates-HA001231351.aspx
;WITH cte
as
(
SELECT table_name.users , rn = ROW_NUMBER() OVER (PARTITION BY users ORDER BY users)
FROM table_name
)
SELECT SUM(users)
FROM cte
WHERE rn = 1
SQL Fiddle
Try here yourself
TEST
DECLARE #table_name Table (Users INT );
INSERT INTO #table_name Values (1),(1),(1),(3),(3),(5),(5);
;WITH cte
as
(
SELECT users , rn = ROW_NUMBER() OVER (PARTITION BY users ORDER BY users)
FROM #table_name
)
SELECT SUM(users) DisSum
FROM cte
WHERE rn = 1
Result
DisSum
9
If circumstances make it difficult to weave a "distinct" into the sum clause, it will usually be possible to add an extra "where" clause to the entire query - something like:
select sum(t.ColToSum)
from SomeTable t
where (select count(*) from SomeTable t1 where t1.ColToSum = t.ColToSum and t1.ID < t.ID) = 0
May be a duplicate to
Trying to sum distinct values SQL
As per Declan_K's answer:
Get the distinct list first...
SELECT SUM(SQ.COST)
FROM
(SELECT DISTINCT [Tracking #] as TRACK,[Ship Cost] as COST FROM YourTable) SQ

ROW_NUMBER() in Redshift to select biggest row from each group?

I need to select one row from each group based on COUNT(1) field.
In other databases I'd use ROW_NUMBER() function, which in redshift is unsupported yet.
The answer is to use a SUM(1) OVER(PARTITION BY group_field ORDER BY order field ROWS UNBOUNDED PRECEDING) construct like that:
SELECT id,
name,
cnt
FROM
(SELECT id,
name,
count(*) cnt,
sum(1) over (partition BY id ORDER BY cnt DESC ROWS UNBOUNDED PRECEDING) AS row_number
FROM table
GROUP BY id,
name)
WHERE row_number = 1
ORDER BY name