MySQL Error Code: 1048: Column cannot be null - mysql

I have a query:
SELECT
COUNT(*)
FROM
(SELECT
vendors_id,
merchants_id,
SUM(amount) AS amount,
SUM(commission_amount) AS commission_amount
FROM
(SELECT
vendors_id,
merchants_id,
amount,
commission_amount
FROM
(SELECT
vendors.id AS vendors_id,
merchants_id,
SUM(transactions_cash.amount) AS amount,
SUM(
transactions_cash.commission_amount
) AS commission_amount
FROM
ibaserver.transactions_cash,
ibaserver.vendors,
ibaserver.merchants
WHERE transactions_cash.vendors_id = vendors.id
AND TIME > 1466680920208
AND TIME <= 1466681880067
AND merchants_id = merchants.id
GROUP BY transactions_cash.merchants_id
ORDER BY transactions_cash.merchants_id) a
UNION
ALL
SELECT
vendors_id,
merchants_id,
amount,
commission_amount
FROM
(SELECT
vendors.id AS vendors_id,
merchants_id,
SUM(
transactions_cash_archive.amount
) AS amount,
SUM(
transactions_cash_archive.commission_amount
) AS commission_amount
FROM
ibaserver.transactions_cash_archive,
ibaserver.vendors,
ibaserver.merchants
WHERE transactions_cash_archive.vendors_id = vendors.id
AND TIME > 1466680920208
AND TIME <= 1466681880067
AND merchants_id = merchants.id
GROUP BY transactions_cash_archive.merchants_id
ORDER BY transactions_cash_archive.merchants_id) b) s) q
And when the inner query
SELECT
vendors_id,
name,
amount
FROM ....
returns the data, the result is returned successfully. If the inner query returns only NULL:
the entire query returns an error:
Error Code: 1048
Column 'vendors_id' cannot be null
How to return 0 in the case when the inner query returns all of a NULL?

The function you want is called COALESCE. COALESCE takes a list of arguments and returns the first non-NULL value from that list. For example the query
SELECT COALESCE(vendors_id, 0), COALESCE(name, ''), COALESCE(amount, 0)...
FROM vendors...
will return either the non-NULL column value or the specified substitution value for each column.

You can use the function:
ISNULL(colName,'new value') AS
For example:
Select A.col1,ISNULL(B.col2,'0') as col2 from Table1 A INNER JOIN Table2 B ON A.cod1=B.cod1

Related

MySql - Selecting MAX & MIN and returning the corresponding rows

I trying to get the last 6 months of the min and max of prices in my table and display them as a group by months. My query is not returning the corresponding rows values, such as the date time for when the max price was or min..
I want to select the min & max prices and the date time they both occurred and the rest of the data for that row...
(the reason why i have concat for report_term, as i need to print this with the dataset when displaying results. e.g. February 2018 -> ...., January 2018 -> ...)
SELECT metal_price_id, CONCAT(MONTHNAME(metal_price_datetime), ' ', YEAR(metal_price_datetime)) AS report_term, max(metal_price) as highest_gold_price, metal_price_datetime FROM metal_prices_v2
WHERE metal_id = 1
AND DATEDIFF(NOW(), metal_price_datetime) BETWEEN 0 AND 180
GROUP BY report_term
ORDER BY metal_price_datetime DESC
I have made an example, extract from my DB:
http://sqlfiddle.com/#!9/617bcb2/4/0
My desired result would be to see the min and max prices grouped by month, date of min, date of max.. and all in the last 6 months.
thanks
UPDATE.
The below code works, but it returns back rows from beyond the 180 days specified. I have just checked, and it is because it joining by the price which may be duplicated a number of times during the years.... see: http://sqlfiddle.com/#!9/5f501b/1
You could use twice inner join on the subselect for min and max
select a.metal_price_datetime
, t1.highest_gold_price
, t1.report_term
, t2.lowest_gold_price
,t2.metal_price_datetime
from metal_prices_v2 a
inner join (
SELECT CONCAT(MONTHNAME(metal_price_datetime), ' ', YEAR(metal_price_datetime)) AS report_term
, max(metal_price) as highest_gold_price
from metal_prices_v2
WHERE metal_id = 1
AND DATEDIFF(NOW(), metal_price_datetime) BETWEEN 0 AND 180
GROUP BY report_term
) t1 on t1.highest_gold_price = a.metal_price
inner join (
select a.metal_price_datetime
, t.lowest_gold_price
, t.report_term
from metal_prices_v2 a
inner join (
SELECT CONCAT(MONTHNAME(metal_price_datetime), ' ', YEAR(metal_price_datetime)) AS report_term
, min(metal_price) as lowest_gold_price
from metal_prices_v2
WHERE metal_id = 1
AND DATEDIFF(NOW(), metal_price_datetime) BETWEEN 0 AND 180
GROUP BY report_term
) t on t.lowest_gold_price = a.metal_price
) t2 on t2.report_term = t1.report_term
simplified version of what you should do so you can learn the working process.
You need calculate the min() max() of the periods you need. That is your first brick on this building.
you have tableA, you calculate min() lets call it R1
SELECT group_field, min() as min_value
FROM TableA
GROUP BY group_field
same for max() call it R2
SELECT group_field, max() as max_value
FROM TableA
GROUP BY group_field
Now you need to bring all the data from original fields so you join each result with your original table
We call those T1 and T2:
SELECT tableA.group_field, tableA.value, tableA.date
FROM tableA
JOIN ( ... .. ) as R1
ON tableA.group_field = R1.group_field
AND tableA.value = R1.min_value
SELECT tableA.group_field, tableA.value, tableA.date
FROM tableA
JOIN ( ... .. ) as R2
ON tableA.group_field = R2.group_field
AND tableA.value = R2.max_value
Now we join T1 and T2.
SELECT *
FROM ( .... ) as T1
JOIN ( .... ) as T2
ON t1.group_field = t2.group_field
So the idea is if you can do a brick, you do the next one. Then you also can add filters like last 6 months or something else you need.
In this case the group_field is the CONCAT() value

Concatenation using a mysql variable

The problem in my query particularly in this piece:
#a:= concat(#a, ',', B.call_account_id) AS paid_account_id
Here is the whole query:
SELECT operator_id, paid_account_ids, SUM( goods_count * price ) AS sales_volume, count(*) AS sales_cnt
FROM (
SELECT B.operator_id, #a:= concat(#a, ',', B.call_account_id) AS paid_account_ids, B.call_time, A.goods_count, A.price, UNIX_TIMESTAMP( A.completion_date ) AS paid_ts
FROM call_module_data B
INNER JOIN ak_accounts A ON ( A.account_id = B.call_account_id AND A.goods_count >=1 )
WHERE B.call_status IN (1,7) AND A.status_id = 5
AND operator_id IN ( $op_ids )
$and_str_accounts
GROUP BY A.account_id
HAVING call_time < (paid_ts + $time_shift)
) AS T
GROUP BY operator_id";
So the expression mentioned above should produce the concatenated string of account ids (e.g 3341,4355,4433...). But I got NULL instead of desired string.
Please help to resolve. Thanks in advance.
Use GROUP_CONCAT() function instead of String concatenation
Change
#a:= concat(#a, ',', B.call_account_id) AS paid_account_id
above string to
GROUP_CONCAT(B.call_account_id) AS paid_account_ids
Final Answer:
SELECT operator_id, GROUP_CONCAT(paid_account_ids) AS paid_account_ids,
SUM(goods_count * price) AS sales_volume, COUNT(*) AS sales_cnt
FROM (SELECT B.operator_id, GROUP_CONCAT(B.call_account_id) AS paid_account_ids,
B.call_time, A.goods_count, A.price,
UNIX_TIMESTAMP(A.completion_date) AS paid_ts
FROM call_module_data B
INNER JOIN ak_accounts A ON A.account_id = B.call_account_id AND A.goods_count >=1
WHERE B.call_status IN (1,7) AND A.status_id = 5 AND operator_id IN ($op_ids)
$and_str_accounts
GROUP BY A.account_id HAVING call_time < (paid_ts + $time_shift)
) AS T
GROUP BY operator_id;

MySQL SELECT Query - Subtract a SUM() value with the combined total of two other SUM() values

I have two SELECT statements that give the values "TotalSales" and "VendorPay_Com". I want to be able to subtract VendorPay_Com from TotalSales within the one MySQL statement to get the value "Outstanding_Funds" but I haven't found a reliable way to do so.
These are my two statements:
Query 1:
SELECT SUM(Price) AS TotalSales
FROM PROPERTY
WHERE Status = 'Sold';
Query 2:
SELECT SUM(AC.Amount) AS VendorPay_Comm
FROM (
SELECT Amount FROM lawyer_pays_vendor
UNION ALL
SELECT CommissionEarned AS `Amount` FROM COMMISSION AS C WHERE C.`status` = 'Paid') AS AC
Any help on this matter would be greatly appreciated :)
You can do it as follows :
select (select ...) - (select ...)
In your example, simply :
select
(
SELECT SUM(Price) AS TotalSales
FROM PROPERTY
WHERE Status = 'Sold'
)
-
(
SELECT SUM(AC.Amount) AS VendorPay_Comm
FROM (
SELECT Amount FROM lawyer_pays_vendor
UNION ALL
SELECT CommissionEarned AS `Amount` FROM COMMISSION AS C WHERE C.`status` = 'Paid') AS AC
) AS Outstanding_Funds
Try
SELECT TotalSales-VendorPay_Comm AS Outstanding_Funds
FROM
(SELECT SUM(Price) AS TotalSales
FROM PROPERTY
WHERE Status = 'Sold') t1,
(SELECT SUM(Amount) AS VendorPay_Comm
FROM (SELECT Amount FROM lawyer_pays_vendor
UNION ALL
SELECT CommissionEarned AS Amount
FROM COMMISSION
WHERE Status = 'Paid') t0) t2
Here is sqlfiddle

mysql self join

I have a table called receiving with 4 columns:
id, date, volume, volume_units
The volume units are always stored as a value of either "Lbs" or "Gals".
I am trying to write an SQL query to get the sum of the volumes in Lbs and Gals for a specific date range. Something along the lines of: (which doesn't work)
SELECT sum(p1.volume) as lbs,
p1.volume_units,
sum(p2.volume) as gals,
p2.volume_units
FROM receiving as p1, receiving as p2
where p1.volume_units = 'Lbs'
and p2.volume_units = 'Gals'
and p1.date between "2012-01-01" and "2012-03-07"
and p2.date between "2012-01-01" and "2012-03-07"
When I run these queries separately the results are way off. I know the join is wrong here, but I don't know what I am doing wrong to fix it.
SELECT SUM(volume) AS total_sum,
volume_units
FROM receiving
WHERE `date` BETWEEN '2012-01-01'
AND '2012-03-07'
GROUP BY volume_units
You can achieve this in one query by using IF(condition,then,else) within the SUM:
SELECT SUM(IF(volume_units="Lbs",volume,0)) as lbs,
SUM(IF(volume_units="Gals",volume,0)) as gals,
FROM receiving
WHERE `date` between "2012-01-01" and "2012-03-07"
This only adds volume if it is of the right unit.
This query will display the totals for each ID.
SELECT s.`id`,
CONCAT(s.TotalLbsVolume, ' ', 'lbs') as TotalLBS,
CONCAT(s.TotalGalVolume, ' ', 'gals') as TotalGAL
FROM
(
SELECT `id`, SUM(`volume`) as TotalLbsVolume
FROM Receiving a INNER JOIN
(
SELECT `id`, SUM(`volume`) as TotalGalVolume
FROM Receiving
WHERE (volume_units = 'Gals') AND
(`date` between '2012-01-01' and '2012-03-07')
GROUP BY `id`
) b ON a.`id` = b.`id`
WHERE (volume_units = 'Lbs') AND
(`date` between '2012-01-01' and '2012-03-07')
GROUP BY `id`
) s
this is a cross join with no visible condition on the join, i don't think you meant that
if you want to sum quantities you don't need to join at all, just group as zerkms did
You can simply group by date and volume_units without self-join.
SELECT date, volume_units, sum(volume) sum_vol
FROM receving
WHERE date between "2012-01-01" and "2012-03-07"
GROUP BY date, volume_units
Sample test:
select d, vol_units, sum(vol) sum_vol
from
(
select 1 id, '2012-03-07' d, 1 vol, 'lbs' vol_units
union
select 2 id, '2012-03-07' d, 2 vol, 'Gals' vol_units
union
select 3 id, '2012-03-08' d, 1 vol, 'lbs' vol_units
union
select 4 id, '2012-03-08' d, 2 vol, 'Gals' vol_units
union
select 5 id, '2012-03-07' d, 10 vol, 'lbs' vol_units
) t
group by d, vol_units

Help speed this MySQL query which is taking too long because of an aggregate function

I am using a following query in MySQL for fetching data from a table. Its taking too long because the conditional check within the aggregate function.Please help how to make it faster
SELECT testcharfield
, SUM(IF (Type = 'pi',quantity, 0)) AS OB
, SUM(IF (Type = 'pe',quantity, 0)) AS CB
FROM Table1
WHERE sequenceID = 6107
GROUP BY testcharfield
If you don't care about records that don't have either of those types, you should get better performance this way:
SELECT testcharfield,
SUM(IF (Type = 'pi', quantity, 0)) AS OB,
SUM(IF (Type = 'pe', quantity, 0)) AS CB
FROM Table1
WHERE Type in ('pi', 'pe')
and sequenceID = 6107
GROUP BY testcharfield
If you don't already have them, consider indexes on testcharfield and testcharfield. I am guessing the cardinality of the Type column would not make it a good candidate for an index, but consider that as well.
SELECT testcharfield, MAX(OB) AS OB, MAX(CB) AS CB FROM
((SELECT testcharfield, SUM(quantity) AS OB, 0 AS CB
FROM Table1
WHERE Type = 'pi' AND sequenceID = 6107
GROUP BY testcharfield)
UNION
(SELECT testcharfield, 0 AS OB, SUM(quantity) AS CB
FROM Table1
WHERE Type = 'pe' AND sequenceID = 6107
GROUP BY testcharfield))
Check your indexes on testcharfield, sequenceID, and Type.
Have you tried getting the totals first and then creating the crosstab columns:
Select Z.testcharfield
, Sum( Case When Z.Type = 'pi' Then Total End ) As OB
, Sum( Case When Z.Type = 'pe' Then Total End ) As CB
From (
Select testcharfield
, SUM(quantity) AS Total
From Table1
Where sequenceID = 6107
And Type In('pi','pe')
Group By testcharfield, Type
) Z
Group By Z.testcharfield