MariaDB 10.4 QUERY or Sub-query Optimization - mariadb

is there a way to optimize this kind of query.
See the given below.
Select KPI.*,
(select sum(NP_2g_crfs) from kpi_table where date_upload = '14/01/2020') as num_sum,
(select sum(NP_2g_den) from kpi_table t1 where t1.id >= kpi_table .id) den_sum,
(select sum(NP_2g_num) from kpi_table t1 where t1.id >= kpi_table .id) num_sum,
(select sum(NP_2g_num) from kpi_table t1 where t1.id >= kpi_table .id) /
(select sum(ROUND(NP_2g_den, 2)) from kpi_table t1 where t1.id >= kpi_table .id) kpi
from kpi_table
WHERE date_upload = '14/01/2020'
Load time is up to 5 mins with 5000 rows.
Thanks in advance.

Window function SUM() should perform better that these correlated subqueries:
SELECT *,
SUM(NP_2g_crfs) OVER() num_sum,
SUM(NP_2g_den) OVER (ORDER BY id DESC) den_sum,
SUM(NP_2g_num) OVER (ORDER BY id DESC) num_sum,
SUM(NP_2g_num) OVER (ORDER BY id DESC) / SUM(ROUND(NP_2g_den, 2)) OVER (ORDER BY id DESC) kpi
FROM kpi_table
WHERE date_upload = '2020-01-14'

Related

Is there any way to accomplish this in IBM DB2 enviroment

In DB2 is there a way to basically say:
case when sku (select * from table1 where tb1field = 'SMOMD') then 'True' end
Okay so this is my query so far, I've been going at this for at least a month now so any help would be great.
select tb4.customer, tb4.sku, tb4.qty, tb4.retqty, tb4.stipqty, tb4.lastdate, tb4.firstdate, tb4.stipdate
from(
--Table 4
select tb3.Customer as Customer, tb3.sku as SKU, tb3.qty as Qty, tb3.retqty as RetQty, tb3.stipqty as STIPQty,
case when tb3.lastdate is null then '00/0000' else substr(tb3.lastdate,5,2)||'/'||substr(tb3.lastdate,1,4) end as LastDate,
case when tb3.firstdate is null then '00/0000' else substr(tb3.firstdate,5,2)||'/'||substr(tb3.firstdate,1,4) end as FirstDate,
case when tb3.stipdate is null then '00/0000' else substr(tb3.stipdate,5,2)||'/'||substr(tb3.stipdate,1,4) end as STIPDate
from(
--Table 3
select tb2.Customer as Customer, tb2.SKU as SKU, tb2.Qty as Qty, tb2.RetQty as RetQty, tb2.STIPQty as STIPQty,
max(case when tb2.TranID in ('010','100') then tb2.datenum end) as LastDate,
min(case when tb2.TranID in ('010','100') then tb2.datenum end) as FirstDate,
case when tb2.RC = '4M' then tb2.datenum end as STIPDate
from(
--Table 2
select tb1.Customer as Customer, tb1.SKU as SKU,
sum(case when tb1.TranID in ('010','100') then abs(tb1.OrdNet) else '0' end) as Qty,
sum(case when tb1.TranID = '500' and tb1.rc != '4M' then abs(tb1.OrdNet) else '0' end) as RetQty,
count(case when tb1.rc = '4M' then tb1.sku end) as STIPQty,
tb1.datenum as datenum, tb1.TranID as tranid, tb1.RC as rc
from(
--Table 1
select distinct stkund as Customer, sthptg||space(1)||stmodl||space(1)||stvari||space(1)||stfarb||space(1)||stgroe as SKU,
stvorg as TranID, stggru as RC, stprg09 as PG9, stprg08 as PG8, stperi as datenum, ormne1 as OrdNet
from st_usus.s_stati_pv
join caspdtau.cospf440 on stadrn = jadr40
where trim(stvert) in ('111S','122S')
and sthptg != 'V'
and aktv40 = 'A'
and stprg01 in ('01','04')
and stprg02 = '01'
and stvorg in ('500','010','100')
and stperi >= '20160100'
) as tb1
group by tb1.Customer, tb1.SKU, tb1.datenum, tb1.tranid, tb1.rc
) as tb2
group by tb2.customer, tb2.sku, tb2.qty, tb2.retqty, tb2.stipqty, tb2.tranid, tb2.rc, tb2.datenum
) as tb3
group by tb3.customer, tb3.sku, tb3.qty, tb3.retqty, tb3.stipqty, tb3.lastdate, tb3.firstdate, tb3.stipdate
) as tb4
order by tb4.Customer, tb4.sku
I'm not going to try to decipher exactly what you're trying to do...
Some general advice, rather than using Nested Table Expressions (NTE)
select <..> from (select <...>from mytable)
Consider Common Table Expressions (CTE)
with
table1 as (select <...> from st_usus.s_stati_pv join caspdtau.cospf440 on stadrn = jadr40)
, table2 as (select <...> from table1)
, table3 as (select <...> from table2)
, table4 as (select <....> from table3)
select <...> from table4;
Each CTE (ie. tableX) can refer to a prior CTE or a physical table/view as needed. The final select can refer to one or more CTE's along with one or more physical tables or views.
Nice thing about building with CTE's, is that you can check your results after each step..
with
table1 as (select <...> from st_usus.s_stati_pv join caspdtau.cospf440 on stadrn = jadr40)
select * from table1;

SQL Server Multiple count dates subselect in same query

I'm trying to figure out a way to pull Order Counts per customer id as well as date of first and last order within a date range from an Orders table where each order has both a buyer_id and seller_id. The Orders table contains OrderNumber, Buyer_ID, Seller_ID, OpenDate, ClosedDate. I can run the following queries individually to achieve my goals, but I would like to have everything in the same query if possible.
Order_Table:
OrderNumber, Buyer_ID, Seller_ID, OpenDate, ClosedDate
Buyer_ID Orders:
select Buyer_ID, COUNT(*)as BuyerOrders
from
(
select Buyer_ID
from Orders
where OpenDate between #StartDate and #EndDate
)
a
group by Buyer_ID
Seller_ID Orders:
select Seller_ID, COUNT(*)as SellerOrders
from
(
select Seller_ID
from Orders
where OpenDate between #StartDate and #EndDate
)
a
group by Seller_ID
Dates of First and Last Order within that range: ??
Any input is greatly appreciated!
Since the result is a union and the same customer_id may have an entry as both buyer and seller, how can I put the information in the same row? My first attempt was to create a temporary table from the result of the Union, but I'm drawing a blank on how to display Buyer OrderCount, Seller OrderCount etc on the same row for each Customer_ID in the resulting table.
select 'Buyer' as Type,
Buyer_ID ID,
Count(*) OrderCount,
Min(OpenDate) FirstOrder,
Max(OpenDate) LastOrder
from Orders
where OpenDate between #StartDate and #EndDate
group by Buyer_ID
union
select 'Seller',
Seller_ID,
Count(*),
Min(OpenDate) FirstOrder,
Max(OpenDate) LastOrder
from Orders
where OpenDate between #StartDate and #EndDate
group by Seller_ID
[EDIT] Yes, a little bit of a cheek accepting my answer, then un-accepting it and changing the question! Anyway, try the following:
;with BuyerFirst (Buyer_ID, RowNum, BuyerCount, OrderID, OpenDate)
As
(select Buyer_ID,
ROW_NUMBER() over (partition by Buyer_ID order by OpenDate, OrderID) as RowNum,
count(*) over (partition by Buyer_ID) As BuyerCount,
OrderID,
OpenDate
from Orders
where OpenDate between #StartDate and #EndDate),
BuyerLast (Buyer_ID, RowNum, OrderID, OpenDate)
As
(select Buyer_ID,
ROW_NUMBER() over (partition by Buyer_ID order by OpenDate Desc, OrderID Desc) as RowNum,
OrderID,
OpenDate
from Orders
where OpenDate between #StartDate and #EndDate),
SellerFirst (Seller_ID, RowNum, SellerCount, OrderID, OpenDate)
As
(select Seller_ID,
ROW_NUMBER() over (partition by Seller_ID order by OpenDate, OrderID) as RowNum,
count(*) over (partition by Buyer_ID) As SellerCount,
OrderID,
OpenDate
from Orders
where OpenDate between #StartDate and #EndDate),
SellerLast (Seller_ID, RowNum, OrderID, OpenDate)
As
(select Seller_ID,
ROW_NUMBER() over (partition by Seller_ID order by OpenDate Desc, OrderID Desc) as RowNum,
OrderID,
OpenDate
from Orders
where OpenDate between #StartDate and #EndDate)
select c.*,
bf.BuyerCount,
bf.OpenDate As BuyerFirstOrderDate,
bf.OrderID As BuyerFirstOrderID,
bl.OpenDate As BuyerLastOrderDate,
bl.OrderID As BuyerLastOrderID,
sf.SellerCount,
sf.OpenDate As SellerFirstOrderDate,
sf.OrderID As SellerFirstOrderID,
sl.OpenDate As SellerLastOrderDate,
sl.OrderID As SellerLastOrderID
from Customers c
left join BuyerFirst bf on c.CustomerID = bf.Buyer_ID and bf.RowNum = 1
left join SellerFirst sf on c.CustomerID = sf.Seller_ID and sf.RowNum = 1
left join BuyerLast bl on c.CustomerID = bl.Buyer_ID and bl.RowNum = 1
left join SellerLast sl on c.CustomerID = sl.Seller_ID and sl.RowNum = 1

Calculating Median in SQL Server 2008 R2

I need to calculate Median for several fields in a query and group it by one of the column. Is there a way to calculate Median easily in SQL Server 2008 R2? I am having trouble calculating it in 2008 R2.
Table structure:
PatientName (need to calculate count group by PatientType)
PatientType (should be used to group the query by),
minutes1,
minutes2,
minutes3,
minutes4,
minutes5
End Result:
PatientCount (Group by PatientType),
Median For minutes1 (Group by PatientType),
Median For minutes2 (Group by PatientType),
Median For minutes3 (Group by PatientType),
Median For minutes4 (Group by PatientType),
Median For minutes5 (Group by PatientType)
You could try this:
SELECT PatientType, minutes1=(
SELECT AVG(1.0 * minutes1)
FROM
(
SELECT t3.minutes1, rn = ROW_NUMBER() OVER (ORDER BY t3.minutes1), c.c
FROM (SELECT minutes1 FROM Table t2 WHERE t1.PatientType=t2.PatientType) t3
CROSS JOIN (SELECT c = COUNT(*) FROM (SELECT minutes1 FROM Table t2 WHERE t1.PatientType=t2.PatientType) t4) AS c
) AS x
WHERE rn IN ((c + 1)/2, (c + 2)/2)
), minutes2=(
SELECT AVG(1.0 * minutes2)
FROM
(
SELECT t3.minutes2, rn = ROW_NUMBER() OVER (ORDER BY t3.minutes1), c.c
FROM (SELECT minutes2 FROM Table t2 WHERE t1.PatientType=t2.PatientType) t3
CROSS JOIN (SELECT c = COUNT(*) FROM (SELECT minutes2 FROM Table t2 WHERE t1.PatientType=t2.PatientType) t4) AS c
) AS x
WHERE rn IN ((c + 1)/2, (c + 2)/2)
), minutes3=(
SELECT AVG(1.0 * minutes1)
FROM
(
SELECT t3.minutes3, rn = ROW_NUMBER() OVER (ORDER BY t3.minutes1), c.c
FROM (SELECT minutes3 FROM Table t2 WHERE t1.PatientType=t2.PatientType) t3
CROSS JOIN (SELECT c = COUNT(*) FROM (SELECT minutes3 FROM Table t2 WHERE t1.PatientType=t2.PatientType) t4) AS c
) AS x
WHERE rn IN ((c + 1)/2, (c + 2)/2)
), minutes4=(
SELECT AVG(1.0 * minutes4)
FROM
(
SELECT t3.minutes1, rn = ROW_NUMBER() OVER (ORDER BY t3.minutes1), c.c
FROM (SELECT minutes4 FROM Table t2 WHERE t1.PatientType=t2.PatientType) t3
CROSS JOIN (SELECT c = COUNT(*) FROM (SELECT minutes4 FROM Table t2 WHERE t1.PatientType=t2.PatientType) t4) AS c
) AS x
WHERE rn IN ((c + 1)/2, (c + 2)/2)
), minutes5=(
SELECT AVG(1.0 * minutes5)
FROM
(
SELECT t3.minutes1, rn = ROW_NUMBER() OVER (ORDER BY t3.minutes1), c.c
FROM (SELECT minutes5 FROM Table t2 WHERE t1.PatientType=t2.PatientType) t3
CROSS JOIN (SELECT c = COUNT(*) FROM (SELECT minutes5 FROM Table t2 WHERE t1.PatientType=t2.PatientType) t4) AS c
) AS x
WHERE rn IN ((c + 1)/2, (c + 2)/2)
)
FROM Table t1
GROUP BY PatientType
and there is probably a much better way, and it could likely be optimized quite a bit.

Return distinct pairs of names which have the same exact items in column

I want to find the distinct pairs of names in the table which have the same exact items in the items column. For instance:
CREATE TABLE t
(
name VARCHAR(255),
item VARCHAR(255)
);
INSERT INTO t VALUES("Alice", "Orange");
INSERT INTO t VALUES("Alice", "Pear");
INSERT INTO t VALUES("Alice", "Lemon");
INSERT INTO t VALUES("Bob", "Orange");
INSERT INTO t VALUES("Bob", "Pear");
INSERT INTO t VALUES("Bob", "Lemon");
INSERT INTO t VALUES("Charlie", "Pear");
INSERT INTO t VALUES("Charlie", "Lemon");
The answer here would be Alice,Bob because they took the exact same items.
I want to do it with double negation (using NOT EXISTS/NOT IN) only which I think is more well-suited to this question, but I couldn't come up with anything that is remotely close to being functional.
This is somewhat similar to this question but I'm using SQLite so I cannot use GROUP_CONCAT() but I was wondering how it would be done using relational division using NOT EXISTS/NOT IN.
To get the number of common items between all pairs of names you can use the following query:
SELECT t1.name AS name1, t2.name AS name2, COUNT(*) AS cnt
FROM t AS t1
INNER JOIN t AS t2 ON t1.item = t2.item AND t1.name < t2.name
GROUP BY t1.name, t2.name
Output:
name1 name2 cnt
------------------------
Alice Bob 3
Alice Charlie 2
Bob Charlie 2
Now all you want is to filter out (name1, name2) pairs having a count that is not equal to the number of items of name1 and name2. You can do this using a HAVING clause with correlated subqueries:
SELECT t1.name AS name1, t2.name AS name2
FROM t AS t1
INNER JOIN t AS t2 ON t1.item = t2.item AND t1.name < t2.name
GROUP BY t1.name, t2.name
HAVING COUNT(*) = (SELECT COUNT(*) FROM t WHERE name = t1.name) AND
COUNT(*) = (SELECT COUNT(*) FROM t WHERE name = t2.name)
Demo here
With compound queries:
SELECT t1.name, t2.name
FROM t AS t1, t AS t2
GROUP BY t1.name, t2.name
HAVING t1.name < t2.name
AND NOT EXISTS (SELECT item FROM t WHERE name = t1.name
EXCEPT
SELECT item FROM t WHERE name = t2.name)
AND NOT EXISTS (SELECT item FROM t WHERE name = t2.name
EXCEPT
SELECT item FROM t WHERE name = t1.name);
Using NOT IN is possible, bit expresses exactly the same mechanism with more complexity:
SELECT t1.name, t2.name
FROM t AS t1, t AS t2
GROUP BY t1.name, t2.name
HAVING t1.name < t2.name
AND NOT EXISTS (SELECT item
FROM t
WHERE name = t1.name
AND item NOT IN (SELECT item
FROM t
WHERE name = t2.name))
AND NOT EXISTS (SELECT item
FROM t
WHERE name = t2.name
AND item NOT IN (SELECT item
FROM t
WHERE name = t1.name));
This seems to be working with SQLLite
select t1.name
from t t1
join t t2 on t1.name <> t2.name and t1.item = t2.item
join (select name, count(*) as cnt from t group by name) t3 on t3.name = t1.name
join (select name, count(*) as cnt from t group by name) t4 on t4.name = t2.name
group by t1.name, t3.cnt, t4.cnt
having count(*) = max(t3.cnt, t4.cnt)
I might have found a solution to your issue. Mine was tested using MySQL, but it's not using GROUP_CONCAT(). It might work for your SQLite database. My query is used to find people who have bought the same exact items.
Try using this statement:
SELECT DISTINCT e1.name, e2.name from t e1, t e2 WHERE e1.item=e2.item AND e1.name != e2.name GROUP BY e1.item HAVING count(*) >1;
https://gyazo.com/5e5e9d0ddfb33cb47439a674297108ed

How to remove null value form multiple column in sql select statement result set

How to achieve the result set in sql query
You could work along
WITH
T1 AS (
SELECT
val,
ROW_NUMBER() OVER (PARTITION BY NULL ORDER BY id) rn
FROM Table1
),
T2 AS (
SELECT
val,
ROW_NUMBER() OVER (PARTITION BY NULL ORDER BY id) rn
FROM Table2
),
T3 AS (
SELECT
val,
ROW_NUMBER() OVER (PARTITION BY NULL ORDER BY id) rn
FROM Table3
)
SELECT
T1.val column1
, T2.val column2
, T3.val column3
FROM T1
JOIN T2
ON T1.rn = T2.rn
JOIN T3
ON T2.rn = T3.rn
ORDER BY T1.rn
;
You'd need to
put the statements, which are now going into the UNION into "T1" through "T3", and
move your current sort orders to the ROW_NUMBER analytic functions respectively.
… and should be done: SQL Fiddle
Please comment, if and as further detail is required.

Resources