Combining multiple cte - sql-server-2008

Is it possible to combine a result of two cte to another cte. I wrote a query combining two cte. The result gave a three column data in which I want to group the third column and averaging the second column. The second column resulted from a case sum statement.

If you are asking whether you can re-use CTEs after they have been used in a query, the answer is no. You can't do this:
with A
as (
-- query
)
select A.*
from A;
-- this is a separate query
select id
, count(*)
from A
group by
id
You can, however, combine CTEs in all kinds of ways, as long as you do it in a single statement. You can do this, which uses the hypothetical CTE A in two CTEs and the final query:
with A
as (
-- some query
)
, ACustomers
as (
select *
from Customers
join A
on ....
)
, AVendors
as (
select *
from Vendors
join A
on ....
)
select A.StateId
, ACount = COUNT(*)
, CustomerCount = (select count(*) from ACustomers ac where ac.StateId = A.StateId )
, VendorCount = (select count(*) from AVendors av where av.StateId = A.StateId )
from A
group by
A.StateId

Related

How do I correctly choose two columns within Sub Selection Mysql

Hello guys Im trying to use select within another Select and I get error of opperan should contain 1 value I saw other answers but coulndt figure out how to apply the solution. So here goes my query:
SELECT a.date_insert AS date
,HOUR(a.date_insert) AS hour
,AVG(spood)
,AVG(factor)
,(SELECT AVG(dd.spood) as median_val1,AVG(dd.factor) as median_val2
FROM (
SELECT d.spood, d.factor, #rownum:=#rownum+1 as `row_number`, #total_rows:=#rownum
FROM traf d, (SELECT #rownum:=0) r
WHERE d.spood is NOT NULL
ORDER BY d.spood
) as dd
WHERE dd.row_number IN ( FLOOR((#total_rows+1)/2), FLOOR((#total_rows+2)/2) ))
FROM traf a
INNER JOIN mycolumn b
ON a.ref_id = b.ref_id where value_3 > 100
GROUP BY 1,2
Please any help would be grateful
** I get the error at the (SELECT AVG) which is the subquery **
opperand should contain 1 column while I wish to retrieve 2 columns
You are selecting two expressions from the sub-query which is in the SELECT clause.
If you are using sub-query in the SELECT clause, It must have only one value in sub-query's SELECT clause and must return only one row.
Try to remove one expression from the sub-query and you will find success.
The error message is pretty clear. You have a subquery in the SELECT clause, which is a scalar subquery:
(SELECT AVG(dd.spood) as median_val1,AVG(dd.factor) as median_val2
FROM (SELECT d.spood, d.factor, #rownum:=#rownum+1 as `row_number`, #total_rows:=#rownum
FROM traf d, (SELECT #rownum:=0) r
WHERE d.spood is NOT NULL
ORDER BY d.spood
) as dd
WHERE dd.row_number IN ( FLOOR((#total_rows+1)/2), FLOOR((#total_rows+2)/2
)
A scalar subquery can only return one column and at most one row. The simple solution is to return only one value in the subquery. If you need multiple values, use multiple subqueries.
It is probably possible to rewrite your overall query. However, your question doesn't provide sample data, desired results, or an explanation of what the query is supposed to be doing.
-- Update
Try using the LEFT JOIN with sub-query as follows:
SELECT a.date_insert AS date
,HOUR(a.date_insert) AS hour
,AVG(spood)
,AVG(factor)
,MAX(AVG_VIEW.median_val1) -- usgae of the values from sub-query
,MAX(AVG_VIEW.median_val1) -- usgae of the values from sub-query
FROM traf a
INNER JOIN mycolumn b
ON a.ref_id = b.ref_id
-- added this
LEFT JOIN (SELECT AVG(dd.spood) as median_val1,AVG(dd.factor) as median_val2
FROM (
SELECT d.spood, d.factor, #rownum:=#rownum+1 as `row_number`, #total_rows:=#rownum
FROM traf d, (SELECT #rownum:=0) r
WHERE d.spood is NOT NULL
ORDER BY d.spood
) as dd
WHERE dd.row_number IN ( FLOOR((#total_rows+1)/2), FLOOR((#total_rows+2)/2) )) AS AVG_VIEW
ON 1=1 -- use proper conditions and accordingly use the correct columns in SELECT of this sub-query
-- till here
where value_3 > 100
GROUP BY 1,2
Note: You need to change this query little bit according to your requirement.

SQL Union Query - Referencing to alias of derived table

I have a complicated aggregate-functions query that produces a result-set, and which has to be amended with a single row that contains the totals and averages of that result-set.
My idea is to assign an alias to the result-set, and then use that alias in a second query, after a UNION ALL statement.
But, I can't successfully use the alias, in the subsequent SELECT statement, after the UNION ALL statement.
For the sake of simplicity, I won't post the original query here, just a simplified list of the variants I've tried:
SELECT * FROM fees AS Test1 WHERE Percentage = 15
UNION ALL
(SELECT * FROM fees AS Test2 WHERE Percentage > 15)
UNION ALL
(SELECT * FROM (SELECT * FROM fees AS Test3 WHERE Percentage < 10) AS Test4)
UNION ALL
SELECT * FROM Test3
The result is:
MySQL said: Documentation
#1146 - Table 'xxxxxx.Test3' doesn't exist
The result is the same if the last query references to the table Test1, Test2, or Test4.
So, how should I assign an alias to a result-set/derived table in earlier queries and use that same alias in latter queries, all within a UNION query?
Amendment:
My primary query is:
SELECT
COALESCE(referrers.name,order_items.ReferrerID),
SUM(order_items.quantity) as QtySold,
ROUND(SUM((order_items.quantity*order_items.price+order_items.shippingcosts)/((100+order_items.vat)/100)), 2) as TotalRevenueNetto,
ROUND(100*SUM(order_items.quantity*order_items.purchasepricenet)/SUM((order_items.quantity*order_items.price+order_items.shippingcosts)/((100+order_items.vat)/100)), 1) as PurchasePrice,
ROUND(100*SUM(order_items.quantity*COALESCE(order_items.calculatedfee,0)+order_items.quantity*COALESCE(order_items.calculatedcost,0))/SUM((order_items.quantity*order_items.price+order_items.shippingcosts)/((100+order_items.vat)/100)), 1) as Costs,
ROUND(100*SUM(order_items.calculatedprofit) / SUM( (order_items.quantity*order_items.price + order_items.shippingcosts)/((100+order_items.vat)/100) ) , 1) as Profit,
COALESCE(round(100*Returns.TotalReturns_Qty/SUM(order_items.quantity),2),0) as TotalReturns
FROM order_items LEFT JOIN (SELECT order_items.ReferrerID as ReferrerID, sum(order_items.quantity) as TotalReturns_Qty FROM order_items WHERE OrderType='returns' and OrderTimeStamp>='2017-12-1 00:00:00' GROUP BY order_items.ReferrerID) as Returns ON Returns.ReferrerID = order_items.ReferrerID LEFT JOIN `referrers` on `referrers`.`referrerId` = `order_items`.`ReferrerID`
WHERE ( ( order_items.BundleItemID in ('-1', '0') and order_items.OrderType in ('order', '') ) or ( order_items.BundleItemID is NULL and order_items.OrderType = 'returns' ) ) and order_items.OrderTimestamp >= '2017-12-1 00:00:00'
GROUP BY order_items.ReferrerID
ORDER BY referrers.name ASC
I want to make a grand-total of all the rows resulting from query above with:
SELECT 'All marketplaces', SUM(QtySold), SUM(TotalRevenueNetto), AVG(PurchasePrice), AVG(Costs), AVG(Profit), AVG(TotalReturns) FROM PrimaryQuery
I want to do this with a single query.
Your query is well-written. You may be able to get a total line by using a surrounding query with a dummy GROUP BY clause and WITH ROLLUP:
SELECT
COALESCE(Referrer, 'All marketplaces'),
SUM(QtySold) AS QtySold,
SUM(TotalRevenueNetto) AS TotalRevenueNetto,
AVG(PurchasePrice) AS PurchasePrice,
AVG(Costs) AS Costs,
AVG(Profit) AS Profit,
AVG(TotalReturns) AS TotalReturns
FROM
(
SELECT
COALESCE(referrers.name,order_items.ReferrerID) AS Referrer,
SUM(order_items.quantity) AS QtySold,
...
) PrimaryQuery
GROUP BY Referrer ASC WITH ROLLUP;
I'm not entirely sure what you are attempting to solve, but I guess something like the following:
Hypothetical 'main' query:
SELECT T1.ID
, Sum(total_grade)/COUNT(subjects) as AverageGrade
FROM A_Table T1
JOIN AnotherTable T2
ON T2.id = T1.id
GROUP BY T1.ID
You want sub resultsets, without having to keep querying the same data.
Edit: I mistakenly thought the linked documentation and method mentioned below was for the current version of mySQL. It is however a draft for a future version, and CTE's are not currently supported.
In the absence of CTE support, I would probably just insert the resultset into a temporary table. Something like:
CREATE TABLE TEMP_TABLE(ID INT, AverageGrade DECIMAL(15, 3))
INSERT INTO TEMP_TABLE
SELECT T1.ID
, Sum(total_grade)/COUNT(subjects) as AverageGrade
FROM A_Table T1
JOIN AnotherTable T2
ON T2.id = T1.id
GROUP BY T1.ID
SELECT ID, AverageGrade FROM TEMP_TABLE WHERE AverageGrade > 5
UNION ALL
SELECT COUNT(ID) AS TotalCount, SUM(AverageGrade) AS Total_AVGGrade FROM TEMP_TABLE
DROP TABLE TEMP_TABLE
(Disclaimer: I'm not too familiar with mySQL, there may be some syntax errors here. The general idea should be clear, though.)
That is, of course, if i had to do it like this, there are probably better ways to achieve the same. See Thorsten Kettner's comments on the matter.
(Previous answer assuming CTE is a posibility:)
A CTE approach looks like:
WITH CTE AS
(
SELECT T1.ID
, Sum(total_grade)/COUNT(subjects) as AverageGrade
FROM A_Table T1
JOIN AnotherTable T2
ON T2.id = T1.id
GROUP BY T1.ID
)
SELECT ID, AverageGrade FROM CTE WHERE AverageGrade > 5
UNION ALL
SELECT COUNT(ID) AS TotalCount, SUM(AverageGrade) AS Total_AVGGrade FROM CTE
You have the error because every query involved in UNION doens't know the alias of other.
DB Engine execute, in your case, 4 queries and then paste them with UNION operation.
Your real table is fees. Test3 is an alias used in the third query.
If you want to process the results of UNION operation, you must encapsulate your queries in a MAIN query.
It looks like you need something like below. Please try
SELECT * FROM fees AS Test2 WHERE Percentage >= 15
UNION ALL
SELECT * FROM fees AS Test3 WHERE Percentage < 10
You can't use a table alias based on a subquery (is not in the scope of the outer united select) you must repeat the code eg:
SELECT * FROM fees AS Test1 WHERE Percentage = 15
UNION ALL
SELECT * FROM fees AS Test2 WHERE Percentage > 15
UNION ALL
SELECT * FROM (
SELECT * FROM fees AS Test3 WHERE Percentage < 10
) AS Test4
UNION ALL
SELECT * FROM fees AS Test3 WHERE Percentage < 10

How to select rows which have the biggest value of a column?

I don't know if my title is understandable or not, may be someone can help edit my title?
All I want to do is, for example:
I have a table like this
Engineering appears 5 times with different article_category_abbr, and I want to select only one row with the biggest value of num.
Here, it will be Engineering-ENG-192, and Geriatrics&Gerontology will be Geriatrics&Gerontology-CLM-26
But I don't know how to do it on the whole table using mysql
Join your table to a subquery which finds the greatest num value for each sc group.
SELECT t1.*
FROM yourTable t1
INNER JOIN
(
SELECT sc, MAX(num) AS max_num
FROM yourTable
GROUP BY sc
) t2
ON t1.sc = t2.sc AND
t1.num = t2.max_num;
You can have a subquery that gets the largest value for each sc and the resulting rows will then be joined with the table itself based from two columns - sc and num.
SELECT a.*
FROM tableName a
INNER JOIN
(
SELECT sc, MAX(num) AS Num
FROM tableName
GROUP BY sc
) b ON a.sc = b.sc
AND a.num = b.num
Here's a Demo
USE MAX function and GROUP BY like this. Here is more information.
SELECT myID, classTitle, subField, MAX(score) FROM myTable GROUP BY myID, classTitle, subField

How do I do SELECT on multiple colums(ex. 2)?

SELECT DName
FROM drugs
WHERE DID IN
(
SELECT DID,SID
FROM transactions
GROUP BY TotalCost
HAVING SID = 1 AND TotalCost > 100
)
Doing such a query inside brackets will give me a result with 2 columns that I need to select results from one of them. In order to use SID in HAVING clause, I need to include it in SELECT operator inside brackets and that's why I am getting 2 columns as a result.
You can't have 2 columns in an IN statement.
You can just remove the SID from the select and only use it in the HAVING. You don't actually need to retrieve the data and your IN clause will work.
You can use EXISTS in the following way:
SELECT DName
FROM drugs
WHERE EXISTS
(
SELECT *
FROM transactions
WHERE SID = 1
AND TotalCost > 100
AND (
drugs.DID = transactions.SID
OR drugs.DID = transactions.DID
)
)
If I understood you correctly then you want something like this:
SELECT DName
FROM drugs
WHERE (DID, SID) IN
(
//Subquery
)
Answer updated. Sorry i have been deleted my previous answer. And thanks to ZoharPeled for reminding that my previous answer's wrong.
If I understood your question, This should works for you :
SELECT DName
FROM drugs
WHERE DID IN (
SELECT DID FROM(
SELECT DID,SID,TotalCost
FROM transactions
GROUP BY TotalCost
HAVING SID = 1 AND TotalCost > 100
) AS T
)
You have a few answers there - but I'll throw an alternative option into the ring:
select DName
from drugs d
inner join (
SELECT DID
FROM transactions
WHERE SID = 1
AND TotalCost > 100
) tx on d.Did =tx.Did
I think (and I'm open to correction here) that if you use something like...
select *
from table
where EXISTS in ( // some subquery )
... the subquery in the EXISTS clause must be run for each row found in table. With an inner join approach, the RDBMS will execute the sql for the inline table once and then hold the results in memory to join back to the other table. For small tables this is fine - but for larger tables there could be a significant performance hit.

Using Distinct in SQL query

Please find the query given below:
SELECT DISTINCT
reco_index_content_code,
reco_index_content_name,
reco_index_content_url
FROM tbl_reco_index_contents
WHERE
reco_index_user_action_at_select = 1
AND user_profile_number = 1
I need to select reco_index_content_name as distinct.
How should the above query be modified, in order to accomplish that, such that there are no duplicate reco_index_content_name rows ?
The standard solution is documented and uses an uncorrelated subquery as follows:
SELECT x.*
FROM my_table x
JOIN
( SELECT grouping_id
, MIN(ordering_id) min_ordering_id
FROM my_table
GROUP
BY grouping_id
) y
ON y.grouping_id = x.grouping_id
AND y.min_ordering_id = x.ordering_id;