I have a table
and I'm trying to write a select statement with ifnull condition for same type value like to get the result as shown in this table
Below is the sql I have tried -
SELECT
type,
memo,
IFNULL( memo, type = type) memo_all,
amount
FROM
table
But I get the same result as memo column in memo_all column with above query as can be seen in this table 3. Please find the sqlfiddle here with above query and table - http://sqlfiddle.com/#!9/55c43f
What am I missing here? Is there any alternative way to get the result as shown in table 2?
Just in case you are using a version of MySQL earlier than 8+, here is an alternative to Gordon's answer which doesn't use window functions:
SELECT
t1.type,
t1.memo,
t2.memo AS memo_all,
t1.amount
FROM yourTable t1
INNER JOIN
(
SELECT type, MAX(memo) AS memo
FROM yourTable
GROUP BY type
) t2
ON t1.type = t2.type;
SELECT t1.*, t2.memo memo_all
FROM `table` t1
JOIN `table` t2 USING (type)
WHERE t2.memo != '';
Solution which uses one source table copy:
SELECT `table`.*, #tmp := CASE WHEN memo = '' THEN #tmp ELSE memo END memo_all
FROM `table`, (SELECT #tmp := '') variable
ORDER BY type, memo DESC;
Use window functions:
SELECT type, memo,
max(memo) over (partition by type) as memo_all
amount
FROM table;
You want to "borrow" the value from another row. A simple scalar function is not going to do that. However, window functions provide this capability.
EDIT:
In older versions of MySQL, you can use a correlated subquery:
SELECT type, memo,
COALESCE(memo,
(SELECT t2.memo
FROM table t2
WHERE t2.type = t.type AND t2.memo IS NOT NULL
LIMIT 1
)
) as memo_all
amount
FROM table t;
Related
I am running this query on MySQL
SELECT ID FROM (
SELECT ID, msisdn
FROM (
SELECT * FROM TT2
)
);
and it is giving this error:
Every derived table must have its own alias.
What's causing this error?
Every derived table (AKA sub-query) must indeed have an alias. I.e. each query in brackets must be given an alias (AS whatever), which can the be used to refer to it in the rest of the outer query.
SELECT ID FROM (
SELECT ID, msisdn FROM (
SELECT * FROM TT2
) AS T
) AS T
In your case, of course, the entire query could be replaced with:
SELECT ID FROM TT2
I think it's asking you to do this:
SELECT ID
FROM (SELECT ID,
msisdn
FROM (SELECT * FROM TT2) as myalias
) as anotheralias;
But why would you write this query in the first place?
Here's a different example that can't be rewritten without aliases ( can't GROUP BY DISTINCT).
Imagine a table called purchases that records purchases made by customers at stores, i.e. it's a many to many table and the software needs to know which customers have made purchases at more than one store:
SELECT DISTINCT customer_id, SUM(1)
FROM ( SELECT DISTINCT customer_id, store_id FROM purchases)
GROUP BY customer_id HAVING 1 < SUM(1);
..will break with the error Every derived table must have its own alias. To fix:
SELECT DISTINCT customer_id, SUM(1)
FROM ( SELECT DISTINCT customer_id, store_id FROM purchases) AS custom
GROUP BY customer_id HAVING 1 < SUM(1);
( Note the AS custom alias).
I arrived here because I thought I should check in SO if there are adequate answers, after a syntax error that gave me this error, or if I could possibly post an answer myself.
OK, the answers here explain what this error is, so not much more to say, but nevertheless I will give my 2 cents, using my own words:
This error is caused by the fact that you basically generate a new table with your subquery for the FROM command.
That's what a derived table is, and as such, it needs to have an alias (actually a name reference to it).
Given the following hypothetical query:
SELECT id, key1
FROM (
SELECT t1.ID id, t2.key1 key1, t2.key2 key2, t2.key3 key3
FROM table1 t1
LEFT JOIN table2 t2 ON t1.id = t2.id
WHERE t2.key3 = 'some-value'
) AS tt
At the end, the whole subquery inside the FROM command will produce the table that is aliased as tt and it will have the following columns id, key1, key2, key3.
Then, with the initial SELECT, we finally select the id and key1 from that generated table (tt).
I am Using the below table
The case_id for two rows. If the case Id is same then I would want to fetch the row that has Test_script_type as automation and ignore the manual. How can I achieve it with a SQL query..If there is only manual fetch the manual row. How can I achieve it with a SQL query. The Output would be like :
Help is appreciated. Thanks for your time In-advance
You could adress this with not exists:
select t.*
from mytable t
where
script_type = 'Automation'
or not exists (
select 1
from mytable t1
where
t1.case_id = t.case_id
and t1.script_name <> t.script_name
and t1.script_type = 'Automation'
)
You can also filter with a correlated subquery:
select t.*
from mytable t
where t.script_type = (
select min(t1.script_type) -- This gives priority to 'Automation' against 'Manual'
from mytable t1
where t1.case_id = t.case_id
)
SELECT t1.*
FROM `table` t1
LEFT JOIN `table` t2 ON t1.case_id = t2.case_id AND t1.script_type != t2.script_type
WHERE t1.script_type = 'automation' OR t2.case_id IS NULL
You could do something like the following:
WITH cte AS (
SELECT T1.CASE_ID, T1.SCRIPT_NAME, T1.SCRIPT_TYPE,
COUNT(T1.CASE_ID) OVER (PARTITION BY T1.CASE_ID) AS cnt
FROM table1 T1
)
SELECT cte.CASE_ID, cte.SCRIPT_NAME, cte.SCRIPT_TYPE
FROM cte
WHERE (cte.cnt > 1 AND UPPER(cte.SCRIPT_TYPE) = UPPER('AUTOMATION'))
OR cte.cnt = 1
The WITH statement adds a column counting how many times the case_id value is duplicated, which helps identify the rows you want to work with.
Here is an example of it working with the data you have provided: SQLFiddle
If you are using MSSQL Server, You may try below query -
SELECT *
FROM (SELECT CASE_ID, SCRIPT_NAME, SCRIPT_TYPE, ROW_NUMBER() OVER(PARTITION BY CASE_ID ORDER BY SCRIPT_TYPE) RN
FROM YOUR_TAB) T
WHERE RN = 1
I have the following database ( with many more rows ):
There are dates and times for which I might have just Temperature, or x-Axis Vibration, or any field. Some timestamps (like the ones in this pic) have missing fields like Z-Axis Vibration
I want to fetch all this data in the following format and convert fields which are not found to 'NA'
I have tried the following query:
select entry_date, entry_time, field_name, ifnull(value, "NA") as value
from tablename
where group_name = "SL1-DSM-1" and
concat(entry_date, " ", entry_time) in
( select distinct(concat(entry_date, " ", entry_time))
from tablename
where timestamp(entry_date, entry_time) between "2019-07-22 00:00:00" and
"2019-07-23 00:00:00" ) and
field_name in (select distinct(field_name) from tablename where group_name =
"SL1-DSM-1");
This is giving me the result:
Is there a way this can be achieved using a single query ? Or in minimum no. of queries so as to make it faster.
NOTE: Currently, I'm using different queries for each group and field, and compiling them into a common format, but I wanted if this could be returned my MySQL itself
You can generate all the rows using cross join and then fill in the missing values. 'N/A' is not a good fill in, because it is a string. Just use NULL.
Something like this:
select entry_date, entry_time, group_name, field_name,
t.value
from (select distinct entry_date, entry_time, group_name
from tablename
) dtg cross join
(select distinct field_name
from tablename
) f left join
tablename t
using (entry_date, entry_time, group_name, field_name)
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
My database structure contains columns: id, name, value, dealer. I want to retrieve row with lowest value for each dealer. I've been trying to mess up with MIN() and GROUP BY, still - no solution.
Solution1:
SELECT t1.* FROM your_table t1
JOIN (
SELECT MIN(value) AS min_value, dealer
FROM your_table
GROUP BY dealer
) AS t2 ON t1.dealer = t2.dealer AND t1.value = t2.min_value
Solution2 (recommended, much faster than solution1):
SELECT t1.* FROM your_table t1
LEFT JOIN your_table t2
ON t1.dealer = t2.dealer AND t1.value > t2.value
WHERE t2.value IS NULL
This problem is very famous, so there is a special page for this in Mysql's manual.
Check this: Rows Holding the Group-wise Maximum/Minimum of a Certain Column
select id,name,MIN(value) as pkvalue,dealer from TABLENAME
group by id,name,dealer;
here you group all rows by id,name,dealer and then you will get min value as pkvalue.
SELECT MIN(value),dealer FROM table_name GROUP BY dealer;
First you need to resolve the lowest value for each dealer, and then retrieve rows having that value for a particular dealer. I would do this that way:
SELECT a.*
FROM your_table AS a
JOIN (SELECT dealer,
Min(value) AS m
FROM your_table
GROUP BY dealer) AS b
ON ( a.dealer= b.dealer
AND a.value = b.m )
Try following:
SELECT dealer, MIN(value) as "Lowest value"
FROM value
GROUP BY dealer;
select id, name, value, dealer from yourtable where dealer
in(select min(dealer) from yourtable group by name, value)
These answers seem to miss the edge case of having multiple minimum values for a dealer and only wanting to return one row.
If you want to only want one value for each dealer you can use row_number partition - group - the table by dealer then order the data by value and id. we have to make the assumption that you will want the row with the smallest id.
SELECT ord_tbl.id,
ord_tbl.name,
ord_tbl.value,
ord_tbl.dealer
FROM (SELECT your_table.*,
ROW_NUMBER() over (PARTITION BY dealer ORDER BY value ASC, ID ASC)
FROM your_table
) AS ord_tbl
WHERE ord_tbl.ROW_NUMBER = 1;
Be careful though that value, id and dealer are indexed. If not this will do a full table scan and can get pretty slow...