Ok so I have a mySQL table of values. Some are positive, some are negative. The negative ones have a - infront of them in the table. I'm using Codeigniter.
I need to sum them all together, but IGNORE the - before the negative values. I just want to sum the numbers, not sum them as negative numbers.
So for example, this is what it does currently:
-55 + -20 = 35
But what I want it to do is:
-55 + -20 = 75
Basically I want to sum the values only, regardless of their positive or negative type.
How can I do this? Here's my query:
$this->db->select_sum('vat')
->from('accounts')->where_in('type', 'Expenses')
->where('date <=', $current_period)
->where('date >=', $previous_period);
Perhaps something like this will work:
$this->db->select('SUM(CASE WHEN vat >= 0 THEN vat ELSE -vat END) AS sum', false)->from('accounts')->where_in('type', 'Expenses')->where('date <=', $current_period)->where('date >=', $previous_period);
This should keep positive numbers in vat positive and convert negative numbers to positive. Note: the false in the select() statement stops CI from auto-escaping the fields.
Also, as picked up from a comment from #shubhansh, you can use MySQL's ABS() method to get the absolute-value instead of the CASE:
$this->db->select('SUM(ABS(vat)) AS sum', false)->from('accounts')->where_in('type', 'Expenses')->where('date <=', $current_period)->where('date >=', $previous_period);
I can think of two ways.
First way: I'm pretty sure CI escapes field names, so to do it this way you need to execute normal query:
$this->db->query('SELECT SUM(AVG(vat)) FROM accounts WHERE ...'); // Replace ... with WHERE parameters
Second way: Or do two queries and sum the results:
$positive = $this->db->select_sum('vat')->from('accounts')->where_in('type', 'Expenses')->where('date <=', $current_period)->where('date >=', $previous_period)->where('vat >=', 0);
$negative = $this->db->select_sum('vat')->from('accounts')->where_in('type', 'Expenses')->where('date <=', $current_period)->where('date >=', $previous_period)->where('vat <', 0);
$result = $positive + abs($negative);
Mind that second option would take longer time to complete as those are two separate queries.
I had the same issue doing a date search on a db level - best I could do was use ABS() since time_diff returns a negative value if the result is in the past. If are working with date_diff or TIME_DIFF use this:
TIME(ABS(TIMEDIFF(TIME(sch_Starts), TIME("22:00:00"))))
it takes the possibly negative result, converts it via ABS and wrap the TIME() around that to convert back to time if u are using time specific functions like me.
Tedious perhaps but it works 100%
You could always try:
where table.field NOT LIKE '%-%'
Related
Whenever I'm using OR in where condition my query is putting date_format() it's working but when I'm using AND it's working fine.
True Query:
SELECT * FROM `tbl_inquiry_trans`
WHERE date_format(follow_updatetime,'%Y-%m-%d') >= '2018-08-02'
AND date_format(follow_updatetime,'%Y-%m-%d') <= '2018-08-02'
AND emp_id=2 or user_id=2
The above query should display specific date data but it's showing all dates data.
Test Query:
SELECT * FROM `tbl_inquiry_trans`
WHERE date_format(follow_updatetime,'%Y-%m-%d') >= '2018-08-02'
AND date_format(follow_updatetime,'%Y-%m-%d') <= '2018-08-02'
AND emp_id=2
When I'm using AND it's showing expected date data but I want to use OR in the where clause.
The and logical operator has a higher precedence than the or operator (i.e., and expressions are evaluated before or expressions, in a similar way you'd calculate a multiplication before calculating an addition in an arithmetic expression). In order to achieve the behavior you wanted, you need to surround the two sides of the or operator with parenthesis:
SELECT *
FROM tbl_inquiry_trans
WHERE date_format(follow_updatetime,'%Y-%m-%d')>='2018-08-02' AND
date_format(follow_updatetime,'%Y-%m-%d')<='2018-08-02' AND
(emp_id=2 OR user_id=2) -- Here
Same answer as #Mureinik, except that I don't think you need to those calls to DATE_FORMAT, because in MySQL it is possible to directly compare dates against string literals. So, the following should suffice:
SELECT *
FROM tbl_inquiry_trans
WHERE
follow_updatetime >= '2018-08-02' AND follow_updatetime < '2018-08-03' AND
(emp_id = 2 OR user_id = 2);
The logic in the above check on follow_updatetime is that any date would match if it were on or after midnight of 2018-08-02 or strictly before midnight of 2018-08-03. This would cover the entire day of 2018-08-02. This version of doing it is preferable to what you had, because it makes it possible to use an index on the follow_updatetime column.
I need an SQL query , with multiple AND's. Let me explain with an example,
For example I want to search in a database for a property , who's price is greater than 1000 and less than 2000 (price is between 1000-2000), and its area is greater than 1000 sqft. and less than 2000 sq ft. (area is between 1000-2000).
So i was guessing that the query could be,
SELECT *
FROM table_name
WHERE (price>1000 AND price<2000) AND (area>1000 AND area<2000)
this is something i need ! Thank you
Your original query looks fine to me, but you can also use BETWEEN if you like, try this:
SELECT * FROM table_name WHERE (price BETWEEN 1001 AND 2000) AND (area BETWEEN 1001 AND 2000);
expr BETWEEN min AND max
If expr is greater than or equal to min and expr is less than or equal to max, BETWEEN returns 1, otherwise it returns 0. This is equivalent to the expression (min <= expr AND expr <= max) if all the arguments are of the same type. Otherwise type conversion takes place according to the rules described in Section 12.2, “Type Conversion in Expression Evaluation”, but applied to all the three arguments
Use between instead of and
SELECT * FROM table_name WHERE (price between 1001 AND 1999) AND (area between 1001 AND 1999)
Use this, i think it will solve your problem. It works for me:
SELECT * FROM table_name WHERE price and area BETWEEN 1001 and 1999.
If we have same values of the parameters, then we can add the condition with and all the parameters.
I would like to dynamically search for a date in my database according to my $data input.
Dates are stored as date-times and are usually displayed as ex: "2016-05-11".
With a MySql DB my clause was:
Select * From Table WHERE ( Table.date LIKE '$data%' )
So if the user enters "20" the results will be all dates that start with 20. If the user enters "2016-05" the results will be all dates that start with 2016-05, making my search perfectly working.
When deploying over a Sql Server 2008. I realized 2 things.
1) If i use the LIKE function as Such
Select * From Table WHERE ( Table.date LIKE '%$data$%')
The function will work for a value of "2016" , but would return 0 results when a value of "2016-" is entered.
2) If i use the function DATETIME as such
Select * From Table WHERE ( DATEPART(year, Table.date) LIKE(OR)= '$data')
The function will return correct values when $data = 2016, but will return nil values when the $data = '201' for example, hence making it not dynamic.
What am i doing wrong?
Implicit conversion is just bad, bad, bad -- in SQL or most other programming languages.
LIKE acts on strings. If you want it to work on strings, then explicitly make sure that the parameters are strings. This is true in MySQL and SQL Server.
If you want to use LIKE on the year, then use DATENAME() rather than DATEPART():
WHERE DATENAME(year, Table.date) LIKE '$data'
However, I would encourage you to think about dates using date-based constructs, such as date ranges.
I just realized my stupid mistake.
I needed to add a wildcard to my LIKE clause using DATEPART as such.
Select * From Table WHERE ( DATEPART(year, Table.date) LIKE = '$data%' ) .
Works perfectly.
But i would love other suggestions to simplify splitting $data into YYYY , MM , DD and then testing each element.
I would strive to keep Table.date free of manipulation, so indexes are used.
Instead you can use a CASE expression to convert the search parameter to a date range by adding the missing parts:
Lower bound:
CASE LENGTH($data)
WHEN 8 THEN $data + '01'
WHEN 7 THEN $data + '-01'
WHEN 5 THEN $data + '01-01'
WHEN 4 THEN $data + '-01-01'
ELSE $data
END
Upper bound:
CASE LENGTH($data)
WHEN 8 THEN DATEADD(MONTH,$data + '01',1)
WHEN 7 THEN DATEADD(MONTH,$data + '-01',1)
WHEN 5 THEN DATEADD(YEAR,$data + '01-01')
WHEN 4 THEN DATEADD(YEAR,$data + '-01-01')
ELSE DATEADD(DAY,$data,1)
END
Requirement is add salary of employee i m using SUM() , salary is in this format 1,00,005.00 so when 1,00,005.00 + 3,00,005.00 it gives result as 4 not actual result ,
this is query ---->
SELECT employee.name, SUM( department.salary ) AS Salary
FROM department
LEFT JOIN employee ON department.employee_id = employee.id
GROUP BY name
Try to remove all "," in salary and then use sum(). you can use mysql replace function
SELECT employee.name, SUM( replace(department.salary,",","") ) AS
Salary FROM department LEFT JOIN employee ON department.employee_id
= employee.id GROUP BY name
The main question is whether your currency is a decimal type or not. Your format "1,00,005.00" with groups of two and three digit makes me wonder.
If it is, if "1,99,997" + "0,00,003" is equal to "2,00,000", then you can use Hắc Huyền Minh's answer and convert it to a decimal equivalent straight away.
Before doing that, though, I would run an acceptance test on the database to verify that all values are indeed in the form you expect. Otherwise you might introduce a bug in the workings. VARCHAR type has no validation whatsoever, and someone could have a salary of "1,0X,000.15" which would be considered equivalent to ten after the conversion.
If your currency is not a decimal type - for example if "1,05,03" means "one pound five shilling three pennies" - then "1,05,03" + "1,19,09" is not "2,24,12" but rather "3,05,00" - since twelve pennies, not ten, make a shilling, and it takes twenty shillings to make a pound.
In this case you either convert it to decimal via weighting, or you select all the rows and do the sum in code instead of in MySQL. It would be possible also to implement a UDF to perform either the sum or the conversion to decimal.
For weighting, you consider that if one pound is made up of 20 shillings, then each shilling is 1/20 of one pound, and so equals 0.05; so "1,05" becomes 1 + 5*0.05 = 1.25. For pennies, twelve pennies make one shilling which is 0.05 pounds, so one penny is 0.05/12 = 0.00416666... (and there you see a difficulty. You will need a larger numeric type to prevent numeric errors from creeping in).
Good morning, banging my head against a wall with this & was hoping to get some advice. I have 3 tables joined to display sales data as below;
Select
a._CommMonth As Month,
Sum(a._CommDue) As Commission,
Sum(a.`Network Paid`) As Company,
Sum(a.Payable) As Adviser,
c.Fee As Charge,
Sum(a.Payable) - (c.Fee) As Total
From
pms_payments.dbo_payments a
Inner Join pms_payments.dbo_nscontacts b
On b._Firm_Name = a._Firm_Name
Left Join pms_payments.dbo_clawback c
On b.ContactID = c.ContactID And a._CommMonth = c.Month
Where
b.ContactID = 199
Group By
a._CommMonth
The Sum(a.Payable) - (c.Fee) As Total field is where I am having issues, if no record exists in c.fee table then nothing is returned such as 100 - [No record] = 100. If a record is present the value is deducted as expected such as 100 - 15 = 85.
Does that make sense?
Thanks
Have a look at using IFNULL
IFNULL(expr1,expr2)
If expr1 is not NULL, IFNULL() returns expr1; otherwise it returns
expr2. IFNULL() returns a numeric or string value, depending on the
context in which it is used.
Something like
Sum(a.Payable) - IFNULL(c.Fee,0)
If I understand your question correctly, instead of getting 100 - no record = 100, you are getting 100 - no record = [nothing].
Presuming this is correct, then I believe your problem stems from the fact that null is not the same as zero (and is not a valid number). You can use the IFNULL() function to replace a null value with zero and your subtraction should work.
Please let me know if I misunderstood the question.
Hi there & thanks to you both, the IFNULL function was exactly what I needed. Sorry I could not accept both answers, really appreciate the effort & time though.
Sum(a.Payable) - IFNULL (c.Fee,0) As Total
Regards
Gary