Related
I tried finding the answer, but maybe I am too new to MSSQL, I come from MySQL, so this is my question super simplified to go straight to the point:
Imagine we have a table "Things"
Thingie | Value
--------+-------
Thing1 | 10
Thing1 | 15
Thing1 | 16
In MySQL I could do something like this in a query:
SET #halfvalue := 0;
SELECT Thingie, Value,
(#halfvalue := Value / 2) AS HalfValue,
(#halfvalue / 2) AS HalfOfHalf
FROM Things
Which would return
Thingie | Value | HalfValue | HalfofHalf
--------+-------+-----------+------------
Thing1 | 10 | 5.00 | 2.50
Thing1 | 15 | 7.50 | 3.75
Thing1 | 16 | 8.00 | 4.00
Looks pretty simple, the actual one is a tad more complicated.
My problem is, in MSSQL I can't assign, and use a variable on the same SELECT. And I can't find anything similar to this functionality on this simple level.
Any solutions?
Edit, this is the select that contains all those nasty operations:
SELECT
fvh.DocEntry,
MAX( fvs.SeriesName ) AS "Serie",
MAX( fvh.DocNum - 1000000 ) AS "Número",
MAX( fvh.DocDate ) AS "Fecha",
MAX( fvh.U_FacNit ) AS "NIT",
MAX( fvh.U_FacNom ) AS "Nombre",
MAX( IIF( ISNULL( fvh.Address, '' ) = '', fvh.Address2, fvh.Address ) ) AS "Dirección",
SUM( fvd.GTotal - ISNULL( ncd.GTotal, 0 ) ) AS "Total",
IIF( MAX( fvh.CANCELED ) = 'Y' OR ( SUM( fvd.GTotal - ISNULL( ncd.GTotal, 0 ) ) = 0 ),
'Anulada',
IIF( SUM( fvd.GTotal ) > SUM( ISNULL( ncd.GTotal, 0 ) ) AND ( SUM( ISNULL( ncd.GTotal, 0 ) ) > 0 ),
'Devuelta',
'Emitida' )
) AS "Estado",
ROUND( ( ( SUM( fvd.GTotal - ISNULL( ncd.GTotal, 0 ) ) / 1.12 ) * 0.12 ), 4 ) AS "IVA",
ROUND( SUM( IIF( fvd.U_TipoA = 'BB',
( fvd.GTotal - ISNULL( ncd.GTotal, 0 ) ) - ( ( ( fvd.GTotal - ISNULL( ncd.GTotal, 0 ) ) / 1.12 ) * 0.12 ),
0 ) ), 4) AS "Bien",
ROUND( SUM( IIF( fvd.U_TipoA = 'S',
( fvd.GTotal - ISNULL( ncd.GTotal, 0 ) ) - ( ( ( fvd.GTotal - ISNULL( ncd.GTotal, 0 ) ) / 1.12 ) * 0.12 ),
0 ) ), 4) AS "Servicio",
ROUND( SUM( IIF( fvd.U_TipoA = 'N',
( fvd.GTotal - ISNULL( ncd.GTotal, 0 ) ) - ( ( ( fvd.GTotal - ISNULL( ncd.GTotal, 0 ) ) / 1.12 ) * 0.12 ),
0 ) ), 4) AS "No Aplica",
COUNT(fvd.LineNum) AS "Lineas", SUM(fvd.GTotal) AS "FCTotal",
SUM(ISNULL( ncd.GTotal, 0 )) AS "NCTotal"
/* Facturas */
FROM OINV AS fvh
LEFT JOIN NNM1 AS fvs ON fvs.Series = fvh.Series
LEFT JOIN INV1 as fvd ON fvd.DocEntry = fvh.DocEntry
/* Notas de Credito */
LEFT JOIN RIN1 AS ncd ON ncd.BaseEntry = fvh.DocEntry AND ncd.LineNum = fvd.LineNum
WHERE fvh.DocDate BETWEEN ? AND ? /*AND fvh.DocEntry = 1108*/
GROUP BY fvh.DocEntry
Thank you all for your time. I will dismantle my query and re-do it taking into consideration all of your input. Gracias, totales.
You think you can do this in MySQL:
SET #halfvalue := 0;
SELECT Thingie, Value,
(#halfvalue := Value / 2) AS HalfValue,
(#halfvalue / 2) AS HalfOfHalf
FROM Things;
But you are wrong. Why? MySQL -- as with every other database -- does not guarantee the order of evaluation of expression in a SELECT. The documentation even warns about this:
In the following statement, you might think that MySQL will evaluate #a first and then do an assignment second:
SELECT #a, #a:=#a+1, ...;
However, the order of evaluation for expressions involving user variables is undefined.
In both databases, you can use a subquery. In the most recent versions of MySQL (and just about any other database), you can also use a CTE:
SELECT Thingie, Value, HalfValue,
(HalfValue / 2) AS HalfOfHalf
FROM (SELECT t.*, (Value / 2) AS HalfValue
FROM Things t
) t;
The answer is simple: you can't do that in MSSQL, because when you try it you'll get:
Msg 141, Level 15, State 1, Line 3
A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations.
which you most probably experienced.
The most simple workaround would be:
SELECT Thingie, Value, Value/2, Value/4 from Things
Other method:
select Thingie, Value, HalfValue, HalfValue / 2 from (
SELECT Thingie, Value, Value / 2 HalfValue from Things
) a
No, that doesn't work in SQL. The parameter value is not set until the query completes. You can do it in two steps:
DECLARE #halfvalue FLOAT = 0;
SELECT #halfvalue = ([Value] / 2)
FROM Things ;
SELECT Thingie
, [Value]
, HalfValue = [Value]/2
, HalfAgainValue = #halfvalue / 2
FROM Things ;
I have this existing query:
SELECT
extension
, Total_Outbound+Total_Missed+Total_Received AS Total_Calls
, Total_Missed
, Total_Talk_Time_minutes
FROM (
SELECT
, extension
, sum(if(Answered = 1,0,1)) AS Total_Missed
, sum(CASE WHEN LEGTYPE1 = 2 AND ANSWERED = 1 THEN 1 ELSE 0 END) AS Total_Received
, sum(if(LEGTYPE1 = 1,1,0)) AS Total_Outbound
, round(sum(Duration) / 60,2) AS Total_Talk_Time_minutes
FROM session a
GROUP BY extension
) x;
It works great but I need to add a metric/formula to it called missed_call_score right under Total_Talk_Time_Minutes.
The formula for the missed call score is this:
(missed calls/total talk time) * (average calls per CSR/total calls) * 100 but one thing to note is that the average calls per csr needs to ignore the MAX and MIN, so the lowest and highest number of calls taken.
I'm not sure how I could construct this score within a single select variable or the syntax I would use for this given the fact that it has to throw out the max and min.
Here is an example of my needed output and the formulas it should be using:
extension | Total calls | missed calls | total talk time | missed call score
----------------------------------------------------------------------------
1234 8 4 15.5 5.7
4321 4 0 9.42 0.0
5678 5 2 6.78 6.5
9876 13 6 18.3 7.2
Total call sum = 30
Total call sum without high and low = 13
average calls per CSR = (13/2) = 6.5
extension 1 = (4/15.5) * (6.5/30) * 100 = 5.7
extension 2 = (0/9.42) * (6.5/30) * 100 = 0.0
extension 3 = (2/6.78) * (6.5/30) * 100 = 6.5
extension 4 = (6/18.3) * (6.5/30) * 100 = 7.2
The data above for extension, total calls, missed calls and talk time are taken from my sql fiddle, linked below. I simply added the score column to give example of my expected output.
The fiddle linked below shows my create and inserts so hopefully that gives everything needed to assist me with this.
**sql fiddle
**
http://sqlfiddle.com/#!9/aa1f9/1
UPDATE
Full production query with joins
SELECT firstn ,
lastn ,
extension ,
Total_Outbound+Total_Missed+Total_Received AS Total_Calls ,
Total_Missed ,
Total_Talk_Time_minutes ,
Total_All_Calls ,
Max_Calls ,
Min_Calls ,
CSR_Count ,
((Total_Missed/Total_Talk_Time_minutes) *
(((Total_All_Calls-Max_Calls-Min_Calls)/CSR_Count)/Total_All_Calls)) * 100
FROM ( SELECT u.firstn ,
u.lastn ,
c.extension ,
sum(if(Answered = 1,0,1)) AS Total_Missed ,
sum(CASE WHEN LEGTYPE1 = 2 AND ANSWERED = 1 THEN 1 ELSE 0 END) AS Total_Received ,
sum(CASE WHEN LEGTYPE1 = 1 THEN 1 ELSE 0 END) AS Total_Outbound ,
round(sum(Duration) / 60,2) AS Total_Talk_Time_minutes ,
(SELECT COUNT(1) FROM ambition.session a INNER JOIN ambition.callsummary b ON a.NOTABLECALLID = b.NOTABLECALLID
INNER join ambition.mxuser c ON a.RESPONSIBLEUSEREXTENSIONID = c.EXTENSIONID
INNER join jackson_id.users u ON c.extension = u.extension
WHERE b.ts between curdate() - interval 5 day and now()
AND c.extension IN (7276,7314,7295,7306,7357,7200,7218,7247,7331,7255,7330,7000,7215,7240,7358,7312)) Total_All_Calls ,
(SELECT MAX(CNT) FROM (SELECT COUNT(1) CNT, c.extension
FROM ambition.SESSION a INNER JOIN ambition.callsummary b ON a.NOTABLECALLID = b.NOTABLECALLID
INNER join ambition.mxuser c ON a.RESPONSIBLEUSEREXTENSIONID = c.EXTENSIONID
INNER join jackson_id.users u ON c.extension = u.extension
WHERE b.ts between curdate() - interval 5 day and now()
AND c.extension IN (7276,7314,7295,7306,7357,7200,7218,7247,7331,7255,7330,7000,7215,7240,7358,7312) GROUP BY responsibleuserextensionid) y) Max_Calls ,
(SELECT MIN(CNT) FROM (SELECT COUNT(1) CNT, c.extension
FROM ambition.SESSION a
INNER JOIN ambition.callsummary b ON a.NOTABLECALLID = b.NOTABLECALLID
INNER join ambition.mxuser c ON a.RESPONSIBLEUSEREXTENSIONID = c.EXTENSIONID
INNER join jackson_id.users u ON c.extension = u.extension
WHERE b.ts between curdate() - interval 5 day and now()
AND c.extension IN (7276,7314,7295,7306,7357,7200,7218,7247,7331,7255,7330,7000,7215,7240,7358,7312)GROUP BY responsibleuserextensionid) y) Min_Calls ,
(SELECT COUNT(DISTINCT c.extension)-2
FROM ambition.SESSION a INNER JOIN ambition.callsummary b ON a.NOTABLECALLID = b.NOTABLECALLID
INNER join ambition.mxuser c ON a.RESPONSIBLEUSEREXTENSIONID = c.EXTENSIONID
INNER join jackson_id.users u ON c.extension = u.extension
WHERE b.ts between curdate() - interval 5 day and now()
AND c.extension IN (7276,7314,7295,7306,7357,7200,7218,7247,7331,7255,7330,7000,7215,7240,7358,7312)) CSR_Count
FROM ambition.session a
INNER JOIN ambition.callsummary b ON a.NOTABLECALLID = b.NOTABLECALLID
INNER join ambition.mxuser c ON a.RESPONSIBLEUSEREXTENSIONID = c.EXTENSIONID
INNER join jackson_id.users u ON c.extension = u.extension
LEFT JOIN ambition.knownnumbers k ON a.callingpartyno = k.phone_number
WHERE b.ts between curdate() - interval 5 day and now()
AND c.extension IN (7276,7314,7295,7306,7357,7200,7218,7247,7331,7255,7330,7000,7215,7240,7358,7312)
GROUP BY c.extension, u.firstn, u.lastn ) x
This should work for you:
SELECT
extension
, Total_Outbound+Total_Missed+Total_Received AS Total_Calls
, Total_Missed
, Total_Talk_Time_minutes
, Total_All_Calls
, Max_Calls
, Min_Calls
, CSR_Count
, ((Total_Missed/Total_Talk_Time_minutes) *
(((Total_All_Calls-Max_Calls-Min_Calls)/CSR_Count)/Total_All_Calls)) * 100
FROM (
SELECT
extension
, sum(if(Answered = 1,0,1)) AS Total_Missed
, sum(CASE WHEN LEGTYPE1 = 2 AND ANSWERED = 1 THEN 1 ELSE 0 END) AS Total_Received
, sum(CASE WHEN ANSWERED = 1 AND LEGTYPE1 = 1 THEN 1 ELSE 0 END) AS Total_Outbound
, round(sum(Duration) / 60,2) AS Total_Talk_Time_minutes
, (SELECT COUNT(1) FROM session) Total_All_Calls
, (SELECT MAX(CNT) FROM (SELECT COUNT(1) CNT, EXTENSION FROM SESSION GROUP BY EXTENSION) y) Max_Calls
, (SELECT MIN(CNT) FROM (SELECT COUNT(1) CNT, EXTENSION FROM SESSION GROUP BY EXTENSION) y) Min_Calls
, (SELECT COUNT(DISTINCT EXTENSION)-2 FROM SESSION) CSR_Count
FROM session a
GROUP BY extension
) x;
Here is the fiddle.
Basically I used sub-counts in your derived table x to get each of the variables needed for missed_call_score. One major thing worth noting is that the logic was off for Total_Outbound, so I tweaked that to a CASE statement instead of an IF(). I selected the count columns in the outer query just so you can see what is going on, you can remove those.
I've done something similar in the past and extracted this snippet from my code.
I think/hope that this might help you getting started (I left out most of the columns from your query and you'd have to adjust avg(amount) to match your formula.
select extension, avg(amount) from
(
select t.*,
min(amount) over (partition by extension) as min_amt,
max(amount) over (partition by extension) as max_amt
from your_table t
) t
where amount > min_amt and amount < max_amt group by extension;
I am trying to answer the question:
How often does a character occur in the first position versus the
second position of a string?
using a SQL query on Mysql.
However I get a syntax error.
The code:
SELECT
onechar,
ASCII(onechar) as asciival,
COUNT(*) as cnt,
SUM(CASE WHEN pos = 1 THEN 1 ELSE 0 END) as pos_1,
SUM(CASE WHEN pos = 2 THEN 1 ELSE 0 END) as pos_2
FROM (
(SELECT
SUBSTRING(`city`, 1, 1) as onechar,
1 as pos
FROM `orders`
WHERE LEN(`city` >= 1 )
UNION ALL
(SELECT
SUBSTRING(`city`, 2, 1) as onechar,
2 as pos
FROM `orders`
WHERE LEN(`city` >= 2)
)
GROUP BY onechar
ORDER BY onechar
The error:
You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use
near 'GROUP BY onechar ORDER BY onechar LIMIT 0, 30' at line 1
Tried several ways without success.
Anyone could give me a light on this problem?
The parenthesis look incorrect and the query is missing an alias for the derived table. Also, because mysql evaluates booleans to 1 or 0 you can simplify your sum statements. Try this:
SELECT onechar, ASCII(onechar) as asciival, COUNT(*) as cnt,
SUM(pos = 1) as pos_1,
SUM(pos = 2) as pos_2
FROM (
SELECT SUBSTRING(`city`, 1, 1) as onechar, 1 as pos
FROM `orders` WHERE LENGTH(`city`) >= 1
UNION ALL
SELECT SUBSTRING(`city`, 2, 1) as onechar, 2 as pos
FROM `orders` WHERE LENGTH(`city`) >= 2
) t
GROUP BY onechar
ORDER BY onechar
You missed a number of closing bracket.
FROM (
(SELECT
SUBSTRING(`city`, 1, 1) as onechar,
1 as pos
FROM `orders`
WHERE LEN(`city` >= 1 )
)
UNION ALL
(SELECT
SUBSTRING(`city`, 2, 1) as onechar,
2 as pos
FROM `orders`
WHERE LEN(`city` >= 2)
)
)
I have tried to run a query I phpmyAdmin as follows
SELECT
orders_history.id,
orders_history.`items`,
orders_history.`transaction_id`,
orders_history.`quantity`,
estockClaims.`esquantity`,
IFNULL( esquantity, 0 ),
orders_history.`quantity` - estockClaims.`esquantity` AS myquantity
FROM orders_history
LEFT JOIN estockClaims
ON orders_history.transaction_id = estockClaims.transaction_id
AND orders_history.items = estockClaims.items
LIMIT 0 , 100
And it gives me this result:
----------------------------------------------------------------------
id items transaction_id quantity esquantity IFNULL(esquantity , 0 ) myquantity
1 FR 001 100 NULL 0 NULL
2 BR 002 10 NULL 0 NULL
3 WR 003 25 25 25 0
4 CR 004 50 3 3 47
How to solve this so that NULL is not NULL anyomre but change to 0. Thanks in advance.
Thanks
You already have it in the next column. What you need to do is to drop the original esquantity column and make an alias for the IFNULL... column, like this:
SELECT orders_history.id, orders_history.`items` , orders_history.`transaction_id` ,
orders_history.`quantity` , IFNULL( esquantity, 0 ) AS esquantity,
orders_history.`quantity` - estockClaims.`esquantity` AS myquantity
FROM orders_history
LEFT JOIN estockClaims ON orders_history.transaction_id = estockClaims.transaction_id
AND orders_history.items = estockClaims.items
LIMIT 0 , 100
The change I mentioned is in the line 2 above.
UPDATE
To get
orders_history.`quantity` - estockClaims.`esquantity` AS myquantity
to show expected results, you need to "unnullify" the esquantity field again so that the subtraction would work:
orders_history.`quantity` - IFNULL( estockClaims.`esquantity`, 0 ) AS myquantity
That would ensure you no longer get, for example:
100 - NULL
but this instead:
100 - 0
which will return a proper value.
You can also skip the whole subtraction thing if esquantity is NULL and simply use the value of quantity.
you can use IF to check the esquantity and myquantity columns:
IF(esquantity IS NULL, 0, esquantity)
and
IF(myquantityIS NULL, 0, myquantity)
or use IFNULL as DanFromGermany said
Reason is you are using it as select instead of when doing subtraction. Use it as below:
SELECT orders_history.id, orders_history.`items` , orders_history.`transaction_id` , orders_history.`quantity` , orders_history.`quantity` - IFNULL( esquantity, 0 ) AS myquantity
FROM orders_history
LEFT JOIN estockClaims ON orders_history.transaction_id = estockClaims.transaction_id
AND orders_history.items = estockClaims.items
LIMIT 0 , 100
select temp.id, items, transaction_id, quantity, ifNULL(esquantity, 0), ifNULL(myquantity, 0)
from (SELECT
orders_history.id,
orders_history.`items`,
orders_history.`transaction_id`,
orders_history.`quantity`,
estockClaims.`esquantity`
orders_history.`quantity` - estockClaims.`esquantity` AS myquantity
FROM orders_history
LEFT JOIN estockClaims
ON orders_history.transaction_id = estockClaims.transaction_id
AND orders_history.items = estockClaims.items
LIMIT 0 , 100) temp
You can also use COALESCE to replace the NULL value to 0
check this query.
SELECT orders_history.id, orders_history.`items` , orders_history.`transaction_id` ,
orders_history.`quantity` , COALESCE( esquantity, 0 ) AS esquantity,
orders_history.`quantity` - COALESCE(estockClaims.`esquantity`, 0) AS myquantity
FROM orders_history
LEFT JOIN estockClaims ON orders_history.transaction_id = estockClaims.transaction_id
AND orders_history.items = estockClaims.items
LIMIT 0 , 100
Table #1: qa_returns_items
Table #2: qa_returns_residues
I have a long time trying to get this Result:
item_code - item_quantity
2 - 1
3 - 2
IF qa_returns_items.item_code = qa_returns_residues.item_code AND status_code = 11 THEN
item_quantity = qa_returns_items.item_quantity -
qa_returns_residues.item_quantity
ELSEIF qa_returns_items.item_code = qa_returns_residues.item_code AND status_code = 12 THEN
item_quantity = qa_returns_items.item_quantity +
qa_returns_residues.item_quantity
ELSE
show diferendes
END IF
I tried this Query:
select SubQueryAlias.item_code,
item_quantity
from (
select
ri.item_code
, case status_code
when 11 then ri.item_quantity - rr.item_quantity
when 12 then ri.item_quantity + rr.item_quantity
end as item_quantity
from qa_returns_residues rr
left join qa_returns_items ri
on ri.item_code = rr.item_code
WHERE ri.returnlog_code = 1
) as SubQueryAlias
where item_quantity > 0 GROUP BY (item_code);
The query returns this result:
item_code - item_quantity
1 - 2
2 - 2
Try this query. I havn't tested it. It is very difficult what you require. But I have built it from table structure and given condition clause.
select qa_returns_items.item_code,
(CASE status_code
WHEN 11 THEN (qa_returns_items.item_quantity - qa_returns_residues.item_quantity)
WHEN 12 THEN (qa_returns_items.item_quantity + qa_returns_residues.item_quantity) END) as item_quantity ,
qa_returns_residues.item_unitprice,
( qa_returns_residues.item_unitprice * item_quant) as item_subtotal,
(qa_returns_residues.item_discount * item_quantity) as item_discount,
( ( qa_returns_residues.item_unitprice * item_quant) -
(qa_returns_residues.item_discount * item_quantity) ) as item_total
where
item_quantity > 0 AND qa_returns_items.item_code = qa_returns_residues.item_code
Update:
select qa_returns_items.item_code,
(CASE status_code
WHEN 11 THEN (qa_returns_items.item_quantity - qa_returns_residues.item_quantity)
WHEN 12 THEN (qa_returns_items.item_quantity + qa_returns_residues.item_quantity) END) as item_quant ,
qa_returns_residues.item_unitprice,
( qa_returns_residues.item_unitprice * item_quant) as item_subtotal,
(qa_returns_residues.item_discount * item_quantity) as item_discount,
( ( qa_returns_residues.item_unitprice * item_quant) -
(qa_returns_residues.item_discount * item_quantity) ) as item_total
where
(CASE status_code
WHEN 11 THEN (qa_returns_items.item_quantity - qa_returns_residues.item_quantity)
WHEN 12 THEN (qa_returns_items.item_quantity + qa_returns_residues.item_quantity) END) item_quant > 0 AND qa_returns_items.item_code = qa_returns_residues.item_code
In my experience I would advice you to start over with a fresh database, no records and start debugging step by step.
First create the database and the tables. After that insert only 2 records with simple data. Afterwards start debugging.
From what I was able to debug the problem is in your sub-select. In the topic you want to see item_code 2 and 3. That can't happen because:
SELECT ri.item_code,
CASE status_code
WHEN 11 then ri.item_quantity - rr.item_quantity
WHEN 12 then ri.item_quantity + rr.item_quantity
END AS item_quantity
FROM qa_returns_residues rr
LEFT JOIN qa_returns_items ri
ON ri.item_code = rr.item_code
WHERE ri.returnlog_code = 1 // Why do you need this for ?
returns
item_code item_quantity
2 2
1 0
1 0
1 0
1 2
And then the main query selects only the results which have item_quantity > 0.
Thus you get only
item_code item_quantity
1 2
2 2
as a result.
I'm not quite sure what's the purpose of this operation but have in mind that simple solutions are always best!
I solved my problem:
SELECT
item_code,
item_quantity,
item_unitprice,
item_subtotal,
item_discount,
item_total
FROM (
SELECT qa_returns_items.item_code,
qa_returns_items.item_quantity,
qa_returns_items.item_unitprice,
qa_returns_items.item_subtotal,
qa_returns_items.item_discount,
qa_returns_items.item_total
FROM qa_returns_items
WHERE returnlog_code = 1
UNION
SELECT qa_returns_residues.item_code,
qa_returns_residues.item_quantity,
qa_returns_residues.item_unitprice,
qa_returns_residues.item_subtotal,
qa_returns_residues.item_discount,
qa_returns_residues.item_total
FROM qa_returns_residues
WHERE returnlog_code = 1
ORDER BY item_code ASC
)
AS SubQueryAlias
WHERE item_code NOT IN (
SELECT a.item_code
FROM qa_returns_items a
JOIN qa_returns_residues b
ON b.item_code = a.item_code
WHERE a.returnlog_code = 1
AND b.returnlog_code = 1
);