SQL - max of a column corresponding to two columns - mysql

A table contains four columns "server", "directory", "usage" and "datetime". All servers has got 10 dirs in common. I need to get the data for a server and it's any dir the usage for the latest datetime in a day.
Say for example if there is a server A with directory B there will be Usage at multiple time for few days. I need the data to be reported by the query for all servers it's all corresponding directory's usage for the latest entry on each day.

If I understood your question correctly, you want to see the last usage for every server and directory. Given a table named "usagestats" with the given columns that would be:
SELECT a.server, a.directory, a.`usage`, a.datetime
FROM usagestats as a INNER JOIN (
SELECT server, directory, max(datetime) datetime
FROM usagestats
GROUP BY server, directory
) AS b ON (
a.server = b.server
and a.directory = b.directory
and a.datetime = b.datetime
)
ORDER BY a.server, a.directory, a.datetime

Im not sure that i understand correctly your question.
MySQL has IF() function, that returns one of statements according to condition in first parameter.
If you want to select data from column where number is bigger and there are only 2 columns - use IF statement like this:
SELECT
if(columnA > columnB, columnA , columnB) as grtColumn,
if(columnA > columnB,'columnA is bigger', 'columnB is bigger') as whichColumnWasGrt
from yourtable;
Help: mysql reference - if() function (there are IF statement and IF() function - diffrent thigs!

Related

MySQL Query that traverses pointer fields

Due to some legacy code, I have 2 MySQL tables with the below structure (simplified):
Invoice (ID, InvoiceNo, First_Item)
InvoiceItem (ID, Details, Next_Item)
Obviously, there are many InvoiceItems for each Invoice.
The legacy app expects you to load the Invoice row first, then load the first item from the InvoiceItem table using the Invoice's First_Item value. To get each successive InvoiceItem row, you would then follow its Next_Item value until you hit a null value.
Is there a way to write MySQL SQL that would bring back all InvoiceItem(s) for a given Invoice? i.e follow the Invoice's First_Item and then traverse all the Invoice_Items's Next_Item pointers.
Thanks
Bill.
You want do a recursive query , but mysql < 8 does not support it .
This is a solution that work on you small dataset ( from sqlfiddle )
select id,
details ,
next_item
from (select * from invoiceitem
order by id ) inv_itm,
(select #iis := 0 ) init
where find_in_set(id, #iis)
and not find_in_set(9999999999, #iis)
and length(#iis := concat(#iis, ',', ifnull(next_item,9999999999))) ;
This solution will work only if for each invoices id of items are in ascending order .
This solution is inspired by How to create a MySQL hierarchical recursive query
You need to plan a upgrade to 5.7 or 8.0 , because bellow you will have no security update soon .
see https://en.wikipedia.org/wiki/MySQL#Release_history

insert a table record into another table

I want to insert a table record into another table. I am selecting user id ,date and variance. When i insert the data of one user it works fine but when i insert multiple records it gives me an error of SQL Error [1292] [22001]: Data truncation: Truncated incorrect time value: '841:52:24.000000'.
insert into
features.Daily_variance_of_time_between_calls(
uId,
date,
varianceBetweenCalls)
SELECT
table_test.uid as uId,
SUBSTRING(table_test.date, 1, 10) as date ,
VARIANCE(table_test.DurationSinceLastCall) as varianceBetweenCalls #calculating the vairiance of inter-event call time
FROM
(SELECT
id,m.uid, m.date,
TIME_TO_SEC(
timediff(m.date,
COALESCE(
(SELECT p.date FROM creditfix.call_logs AS p
WHERE
p.uid = m.uid
AND
p.`type` in (1,2)
AND
(p.id < m.id AND p.date < m.date )
ORDER BY m.date DESC, p.duration
DESC LIMIT 1 ), m.date))
) AS DurationSinceLastCall,
COUNT(1)
FROM
(select distinct id, duration, date,uid from creditfix.call_logs as cl ) AS m
WHERE
m.uId is not NULL
AND
m.duration > 0
# AND
# m.uId=171
GROUP BY 1,2
) table_test
GROUP BY 1,2
If i remove the comment it works fine for one specific user.
Let's start with the error message:
Data truncation: Truncated incorrect time value: '841:52:24.000000'
This message suggests that at some stage MySQL is running into a value which it cannot convert to a date/time/datetime. Efforts in isolating the issue should therefore begin with a focus on where values are being converted to those data types.
Without knowing the data types of all the fields used, it's difficult to say where the problem is likely to be. However, once we knew that the query on it's own ran without complaint, we also then knew that the problem had to be with a conversion happening during the insert itself. Something in the selected data wasn't a valid date, but was being inserted into a date field. Although dates and times and involved in your calculation of varianceBetweenCalls, variance itself returns a numeric data type. Therefore I deduced the problem had to be with the data returned by SUBSTRING(table_test.date, 1, 10) which was being inserted into the date field.
As per the comments, this turned out to be correct. You can exclude the bad data and allow the insert to work by adding the clause:
WHERE
table_test.date NOT LIKE '841%'
AND table_test.DurationSinceLastCall NOT LIKE '841%' -- I actually think this line is not required.
Alternatively, you can retrieve only the bad data (with a view to fixing it), by removing the INSERT and using the clause
WHERE
table_test.date LIKE '841%'
OR table_test.DurationSinceLastCall LIKE '841%' -- I actually think this line is not required.
or better
SELECT *
FROM creditfix.call_logs m
WHERE m.date LIKE '841%'
However, I'm not sure the data type of that field, so you may need to to it like this:
SELECT *
FROM creditfix.call_logs m
WHERE SUBSTRING(m.date,10) LIKE '841%'
Once you correct the offending data, you should be able to remove the "fix" from your INSERT/SELECT statement, though it would be wise to investigate how the bad data got into the system.

Msql Explain Query not the same Test vs local

I just dump the DB from test machine to local machine and run my query below:
SELECT advert_id,A.category_id,A.subcategory_id,subcategory,model_id,model,make,price,price2,gst,cndtn,currency,photo_id, SUM(S.visits) AS visits
FROM adverts A
LEFT JOIN subcategories SC ON A.subcategory_id = SC.subcategory_id
LEFT JOIN photos P ON P.sale_id = A.advert_id AND P.thumb=1 AND P.sale_type_id=1
LEFT JOIN (
SELECT
entity_id , visits
FROM
sitestats_ga
WHERE
entity_type_id=1 AND (date <= DATE_FORMAT(NOW(), "%Y%m%d") && date >= DATE_FORMAT(DATE_SUB(NOW(), INTERVAL 10 DAY), "%Y%m%d"))
) S ON A.advert_id = S.entity_id
WHERE '2015-12-02 06:44:55' >= A.datetime_added AND '2015-12-02 06:44:55' < A.datetime_removed AND A.sold_currency = '' AND (A.subcategory_id = '500' OR A.category_id = '100')
GROUP BY A.advert_id
ORDER BY visits DESC, A.datetime_added DESC
LIMIT 0,12
Unfortunately the result duration is different between TEST and LOCAL, to verify this I tried using EXPLAIN in mysql and they were different also.
Explain result on TEST
Explain result on LOCAL
Just take note that I had a fresh dump of database to my local , which means they have the same indexes and I already verified it after seeing the EXPLAIN results.
Got lucky today and run the query on PROD and the result is the same as my LOCAL, I am expecting that TEST should be the same on PROD but I think there's a discrepancy on DB , so now I want to fix the TEST environment.
How can I dig more on this issue? What do I have to do more?
What happened there is very possible because sometimes Mysql index are not exactly equal in different environment even you have the same amount of data. It is all because how you manipulate the data. For example when you delete data the index number may not refresh again for all the data, so you may still have some index pointing to the empty data. However, when you do explain , this empty index still being scanned.
You can do a test create a fresh index on one column and start insert and delete data. then re-create the same index name it different, sometimes you will see the different index number.

sql select to extract and link the record above

I need some assistance with my extract. Below is a view of my data and how it is extract from a MS SQL database.
My challenge is that the database does not differentiate from the different "email address" . How do I link email address record to the record above.
Secid|Name|Question|Answer|
2|load1|Name of Principle|Joe Make|
2|load1|Contact Number|12234423|
2|load1|Email address|joemake#mymail.com|
2|load1|Name of Principle|Amy Soup|
2|load1|Contact Number of Principle|23134|
2|load1|Email address|amysoup#mymail.com|
2|load1|Name of Teacher|james blue|
2|load1|Contact Number|8787878|
2|load1|Email Address|jamesblue#mymail.com|
2|load1|Name of Secretary|CHARLES black|
2|load1|Contact Number|989897|
2|load1|Email Address|chblack#mymail.com|
If you don't have any column to order by (e.g. a monotonically increasing identity column, or a timestamp), I'm afraid you're honestly out of luck. There is no way to guarantee any sort of ordering of the rows for any query.
What you can do, however, is export the data into an Excel sheet and then look at it manually and put the rows in the right order, assuming you can figure it out. Unfortunately this is really going to be the only way.
If you had a column you could order by, you can use a join to group the rows, assuming you had a way of identifying the start of each set - in your case a Question like 'Name of %' should probably work. Assuming an identity column called Id, something like:
select t.*, tGroupStart.Id as GroupId
from myTable t
join myTable tGroupStart on tGroupStart.Id <= t.Id
and tGroupStart.Question like 'Name of %'
where not exists (
select 1
from myTable t2
where t2.Id <= t.Id
and t2.Question like 'Name of %'
and t2.Id > tGroupStart.Id
)

MySQL query using info from seperate tables

I have a rather complex SQL query that I am looking for a little help with.
I have two tables: a history table and a details table.
The history table contains the following columns.
Event Date(ev_date)
Event Code(ev_code)
Machine ID(mc_id)
The Details table contains the following columns:
Machine ID(mc_id),
Location ID(lo_id)
Machine Name(mc_name)
I need a query that returns the count of the number of events from the history table between a given date range of a given group of machines given by Location ID.
So, kinda in sudo code:
SELECT COUNT(*)
FROM history
WHERE ev_date (BETWEEN start_date AND end_date) AND ev_code = 1 AND ????
(mc_id must have certain lo_id from details table).
Does this make sense?
Thanks
SELECT COUNT(*)
FROM history h
WHERE h.ev_date BETWEEN #start_date AND #end_date
AND ev_code = 1
AND EXISTS(SELECT NULL
FROM details d
WHERE h.mc_id = d.mc_id
AND d.lo_id = #LocationID);
Assuming you have a one-to-one mapping between history and details on mc_id:
SELECT COUNT(*)
FROM history h
JOIN details d USING mc_id
WHERE h.ev_code = 1
AND h.ev_date between start_date and end_date
AND d.lo_id IN (?, ?, ?, ...)
Alternatively ON h.mc_id = d.mc_id instead of USING mc_id.