SQL Arithmetics on rows - sql-server-2008

I'm trying to find the difference between row 2 and row 1(2-1) for each column,I'm lost on how to approach this, I might be doing this wrong from the beginning for all I know.
The 2 sub queries return the rows I'm interested in and the rest is me trying to put them together in a table to operate operate on them, but needing direction ATM
SELECT ROW_NUMBER() OVER(ORDER BY totalhopper_01 ASC) AS rownum,TotalHopper_01,TotalHopper_02,TotalHopper_03,TotalHopper_05,TotalHopper_06 FROM
(
SELECT * FROM(
SELECT TOP 1 TotalHopper_01,TotalHopper_02,TotalHopper_03,TotalHopper_05,TotalHopper_06 FROM mm_Cycle_Data
WHERE TotalHopper_01 IS NOT NULL
AND TotalHopper_02 IS NOT NULL
AND TotalHopper_03 IS NOT NULL
AND TotalHopper_05 IS NOT NULL
AND TotalHopper_06 IS NOT NULL
AND get_address=38 AND t_stamp> '2015-10-28 07:00:00' ORDER BY t_stamp ASC)a
UNION
SELECT * FROM (
SELECT TOP 1 TotalHopper_01,TotalHopper_02,TotalHopper_03,TotalHopper_05,TotalHopper_06 FROM mm_Cycle_Data
WHERE
TotalHopper_01 IS NOT NULL
AND TotalHopper_02 IS NOT NULL
AND TotalHopper_03 IS NOT NULL
AND TotalHopper_05 IS NOT NULL
AND TotalHopper_06 IS NOT NULL
AND get_address=38 AND t_stamp> '2015-11-17 07:00:00' ORDER BY t_stamp ASC)b
)c
Results
rownum TotalHopper_01 TotalHopper_02 TotalHopper_03 TotalHopper_05 TotalHopper_06
-------------------- -------------- -------------- -------------- -------------- --------------
1 182450272 8343796 2539352 0 0
2 339742596 19222977 4940526 0 0

perhaps create a temp table and populate with required data first then run your query ??
INSERT INTO #TempTable (TotalHopper_01,TotalHopper_02,TotalHopper_03,TotalHopper_05,TotalHopper_06)
select TOP 1 TotalHopper_01,TotalHopper_02,TotalHopper_03,TotalHopper_05,TotalHopper_06
FROM mm_Cycle_Data
WHERE TotalHopper_01 IS NOT NULL
AND TotalHopper_02 IS NOT NULL
AND TotalHopper_03 IS NOT NULL
AND TotalHopper_05 IS NOT NULL
AND TotalHopper_06 IS NOT NULL
AND get_address=38 AND t_stamp> '2015-10-28 07:00:00' ORDER BY t_stamp ASC
INSERT INTO #TempTable (TotalHopper_01,TotalHopper_02,TotalHopper_03,TotalHopper_05,TotalHopper_06)
select TOP 1 TotalHopper_01,TotalHopper_02,TotalHopper_03,TotalHopper_05,TotalHopper_06
FROM mm_Cycle_Data
WHERE TotalHopper_01 IS NOT NULL
AND TotalHopper_02 IS NOT NULL
AND TotalHopper_03 IS NOT NULL
AND TotalHopper_05 IS NOT NULL
AND TotalHopper_06 IS NOT NULL
AND get_address=38 AND t_stamp> '2015-11-17 07:00:00' ORDER BY t_stamp ASC
-- get summary of data
SELECT SUM(TotalHopper_01) as totalHopper_01,SUM(TotalHopper_02) as totalHopper_02
FROM #TempTable
-- clean up the temp table when finished
DROP TABLE #TempTable

Related

Sum qty but result is weird in Mysql

I'm using MySQL query to sum qty, but the result a little bit weird, this is my query"
SELECT SUM(qty) FROM inventory_logs
WHERE product_id =12 AND `type` = 'is' AND deleted_at IS null
The data I want to sum:
The result:
4.440892098500626e-16
For additional info, the data type qty column is VARCHAR.
So as I mentioned in my comment, you will need to CAST your varchar values into decimal values and then sum them.
This should do the trick:
SELECT
FORMAT(CAST(SUM(qty) AS DECIMAL(12,2)),2) AS qty_sum
FROM
inventory_logs
WHERE
product_id =12 AND `type` = 'is' AND deleted_at IS null
Test fiddle here.
Use this simple trick to make a number of it, but because of the fractal you need also to use a Round for
SELECT ROUND(SUM(qty + 0),2) FROM inventory_logs
WHERE product_id =12 AND `type` = 'is' AND deleted_at IS null
Schema (MySQL v5.7)
CREATE TABLE inventory_logs (
qty VARCHAR(5)
);
INSERT INTO inventory_logs(qty) VALUES('0');
INSERT INTO inventory_logs(qty) VALUES('2.74');
INSERT INTO inventory_logs(qty) VALUES('1.07');
INSERT INTO inventory_logs(qty) VALUES('-3.81');
INSERT INTO inventory_logs(qty) VALUES('3.81');
INSERT INTO inventory_logs(qty) VALUES('-3.81');
Query #1
SELECT ROUND(SUM(qty + 0),2) FROM inventory_logs;
| ROUND(SUM(qty + 0),2) |
| --------------------- |
| 0 |
View on DB Fiddle
Add a 0 to the SUM function it should work:
SELECT SUM(qty + 0) FROM inventory_logs
WHERE product_id =12 AND `type` = 'is' AND deleted_at IS null

Mysql query to filter out data based on two logic

This is a sample table:
sample_id | timestamp | p_id
============================================
62054 | 2018-09-25 10:18:15 | 2652
62054 | 2018-09-27 16:44:57 | 966
62046 | null | 1809
62046 | 2018-09-25 10:18:15 | 2097
We need to filter out unique sample_id column, but the logic is
IF the timestamp column is null, then return those null column data
62046 | null | 1809
IF the timestamp column is not null, then return the latest timestamp column data
62054 | 2018-09-27 16:44:57 | 966
So its great if anyone provide the sql query.
We need somethings like that,
WHERE
IF(
NOT NULL = all row group by sample_id,
row where cancelled_at is maximum,
null column
)
This query should give you the results you want. It looks for a row with a NULL timestamp, or a row which has a non-NULL timestamp which is the maximum timestamp for that sample_id, but only if there isn't a row for that sample_id which has a NULL timestamp:
SELECT *
FROM table1 t1
WHERE timestamp IS NULL OR
timestamp = (SELECT MAX(timestamp)
FROM table1 t2
WHERE t2.sample_id = t1.sample_id) AND
NOT EXISTS (SELECT *
FROM table1 t3
WHERE t3.sample_id = t1.sample_id AND
t3.timestamp IS NULL)
Output:
sample_id timestamp p_id
62054 2018-09-27T16:44:57Z 966
62046 (null) 1809
Using variables:
SELECT sample_id, timestamp, p_id
FROM (
SELECT sample_id, timestamp, p_id,
#seq := IF(#s_id = sample_id, #seq + 1,
IF(#s_id := sample_id, 1, 1)) AS seq
FROM mytable
CROSS JOIN (SELECT #s_id := 0, #seq := 0) AS vars
ORDER BY
sample_id,
CASE
WHEN timestamp IS NULL THEN 1
ELSE 2
END,
timestamp DESC
) AS t
WHERE t.seq = 1;
Demo
Explanation:
To understand how this works you need to execute the subquery and examine the output it produces:
SELECT sample_id, timestamp, p_id,
#seq := IF(#s_id = sample_id, #seq + 1,
IF(#s_id := sample_id, 1, 1)) AS seq
FROM mytable
CROSS JOIN (SELECT #s_id := 0, #seq := 0) AS vars
ORDER BY
sample_id,
CASE
WHEN timestamp IS NULL THEN 1
ELSE 2
END,
timestamp DESC
Output:
sample_id timestamp p_id seq
-------------------------------------------
62046 NULL 1809 1
62046 25.09.2018 10:18:15 2097 2
62054 27.09.2018 16:44:57 966 1
62054 25.09.2018 10:18:15 2652 2
You can see here that calculated field seq is used to prioritize records inside each sample_id slice.
Note: If you're on MySQL 8.0 you can use window functions to implement the same logic.
Find out those records where time is not null and filter out
timestamp nulls sample_id and for null timestamp
Use union
select * from t1 where (t1.sample_id,t1.timestamp)
in (
SELECT t.sample_id,max(t.timestamp) AS time
FROM t1 t
WHERE t.sample_id NOT IN (select sample_id from t1 where t1.timestamp is null)
GROUP BY t.sample_id
)
UNION
SELECT *
FROM t1 t
WHERE t.timestamp IS NULL
output
sample_id timestamp p_id
62054 2018-09-27 16:44:57 966
62046 null 1809
Group by on the sample_id.
Using If() function, check if the minimum value of the timestamp for the group is null or not. If it is null, return null, else return the Max() value.
Try the following query:
SELECT sample_id,
IF(MIN(timestamp) IS NULL,
NULL,
MAX(timestamp)) AS timestamp
FROM your_table
GROUP BY sample_id

Sum only if all grouped rows are not null, else return null

I have a table like this:
item_id quantity
1 2
1 3
2 NULL
2 4
3 NULL
3 NULL
And now I'm doing a SELECT like this:
SELECT
sum(`quantity`) AS `total_quantity`,
FROM `items`
GROUP BY `item_id`
Now, it return repectively 5, 4, and NULL, but I want 5, NULL and NULL.
I want that if there is a NULL value in the grouped rows, the sum should be NULL, and not the sum of the lines whose columns are not null. How can I achieve that?
Thanks!
You can use only case statement to check if any row of a group contains null as quantity
SELECT item_id,
CASE WHEN SUM(quantity IS NULL) > 0
THEN NULL
ELSE SUM(quantity)
END quantity
FROM items
GROUP BY item_id
using #Abhik Chakraborty's fiddle
DEMO
Thats kind if weird output, in most cases the request is to replace null with 0 or something else, however here is a way to do it
select
x.item_id,
max(x.quantity) as quantity from (
SELECT
t1.item_id,
#sm:= if(#prev_item = item_id, #sm_qty+quantity,quantity) as quantity,
#prev_item :=item_id,
#sm_qty:= quantity
from items t1,(select #prev_item:=null,#sm_qty=0)x
order by item_id
)x
group by x.item_id;
http://www.sqlfiddle.com/#!9/ccb36/13
SELECT * FROM (
( -- Get all not null quantities
SELECT
`i1`.`item_id`,
sum(`i1`.`quantity`) AS `total_quantity`
FROM `items` AS `i1`
WHERE `i1`.`item_id` NOT IN ( SELECT `i2`.`item_id` FROM `items` AS `i2` WHERE `i2`.`quantity` IS NULL )
GROUP BY `item_id`
)
UNION ALL
( -- Get all null quantities
SELECT
`i3`.`item_id`,
null AS `i3`.`total_quantity`
FROM `items` AS `i3`
WHERE `i3`.`item_id` IN ( SELECT `i4`.`item_id` FROM `items` AS `i4` WHERE `i4`.`quantity` IS NULL )
GROUP BY `i3.item_id`
)
) AS items_table
ORDER BY items_table.item_id

INSERT SELECT ON DUPLICATE not updating

Short
I want to SUM a column in TABLE_A based on CRITERIA X and insert into TABLE_B.total_x
I want to SUM a column in TABLE_A based on CRITERIA Y and insert into TABLE_B.total_y
Problem: Step 2 does not update TABLE_B.total_y
LONG
TABLE_A: Data
| year | month | type | total |
---------------------------------------
| 2013 | 11 | down | 100 |
| 2013 | 11 | down | 50 |
| 2013 | 11 | up | 60 |
| 2013 | 10 | down | 200 |
| 2013 | 10 | up | 15 |
| 2013 | 10 | up | 9 |
TABLE_B: structure
CREATE TABLE `TABLE_B` (
`year` INT(4) NULL DEFAULT NULL,
`month` INT(2) UNSIGNED ZEROFILL NULL DEFAULT NULL,
`total_x` INT(10) NULL DEFAULT NULL,
`total_y` INT(10) NULL DEFAULT NULL,
UNIQUE INDEX `unique` (`year`, `month`)
)
SQL: CRITERIA_X
INSERT INTO TABLE_B (
`year`, `month`, `total_x`
)
SELECT
t.`year`, t.`month`,
SUM(t.`total`) as total_x
FROM TABLE_A t
WHERE
t.`type` = 'down'
GROUP BY
t.`year`, t.`month`
ON DUPLICATE KEY UPDATE
`total_x` = total_x
;
SQL: CRITERIA_Y
INSERT INTO TABLE_B (
`year`, `month`, `total_y`
)
SELECT
t.`year`, t.`month`,
SUM(t.`total`) as total_y
FROM TABLE_A t
WHERE
t.`type` = 'up'
GROUP BY
t.`year`, t.`month`
ON DUPLICATE KEY UPDATE
`total_y` = total_y
;
The second SQL (CRITERIA_Y) does not update total_y as expected. WHY?
I would do it another way
insert into TABLE_B (year, month, total_x, total_y)
select year, month
, sum (case [type] when 'down' then [total] else 0 end) [total_x]
, sum (case [type] when 'up' then [total] else 0 end) [total_y]
from TABLE_A
group by [year], [month]
Or using two subqueries way would be
insert into TABLE_B (year, month, total_x, total_y)
select coalesce(t1.year, t2.year) year
, coalesce(t1.month, t2.month) month
, t1.total_x total_x
, t2.total_y total_y
from (select year, month, sum(total) total_x
from TABLE_A where [type]='down') t1
full outer join
(select year, month, sum(total) total_y
from TABLE_A where [type]='up') t2
on t1.year = t2.year and t1.month = t2.month
Or using union
insert into TABLE_B (year, month, total_x, total_y)
select year, month, sum(total_x), sum(total_y)
from (
select year, month, sum(total) total_x, 0 total_y
from TABLE_A where [type]='down'
group by year, month
union
select year, month, 0 total_x, sum(total) total_y
from TABLE_A where [type]='up'
group by year, month) t
group by year, month
Reading specs on INSERT...ON DUPLICATE KEY UPDATE, I noticed this:
If ... matches several rows, only one row is updated. In general, you should try to avoid using an ON DUPLICATE KEY UPDATE clause on tables with multiple unique indexes.
So syntax with composite key is kind of cumbersome, and I personally would avoid using it.

MYSQL: BASIC SELECT with != statemenet

SELECT id, company_id, user_id, valid_until, price
FROM `classifieds`
WHERE `user_id` = 1
AND `valid_until` > now()
AND `price` = -2
this query gives me one row, and it works ok...
as soon as i add a statement
SELECT id, company_id, user_id, valid_until, price
FROM `classifieds`
WHERE `user_id` = 1
AND `valid_until` > now()
AND `price` = -2
AND `company_id` != 23
it gives me nothing!!!
the row I am getting in first query has company_id NULL
id company_id user_id valid_until price
35136 NULL 1 2012-02-12 08:06:37 -2
Please advise
EDIT:
I don't want rows that have company_id NULL. I want ALL rows (NULL and not NULL) except for (company_id) value 23.
SELECT id, company_id, user_id, valid_until, price
FROM `classifieds`
WHERE `user_id` = 1
AND `valid_until` > now()
AND `price` = -2
AND (`company_id` IS NULL OR `company_id` != 23)
this seems to do the trick