Create a last url column from current list of hits - mysql

I currently have the following columns:
hit_id, visit_id, timestamp, page_url, page_next
hit_id increments upwards
visit_id is an ID of the visit and unique to each visitor
timestamp is a unix timestamp of the hit
page_url is the page being looked at
page_next is the page that was looked at next
I would like to to add a new column, page_last, where the previous page URL would go into - I should be able to extract this from page_url and page_next. I do not know why I did not create this column in the first place, probably a slight over-site really.
Is there anyway to fill this column using some MySQL trickery? page_last would always be empty on the initial hit on the website (doesn't contain referrer website).

I find the name page_last ambiguous (does it mean the previous page? or this last page on the visit?). I suggest you change it to page_prev.
The following comes close to filling this in, assuming that no one visited the same page multiple times in a visit:
select h.*, hprev.page_url as page_prev
from hits h left outer join
hits hprev
on hprev.page_next = h.page_url and hprev.visit_id = h.visit_id
If that is not true, then you need the most recent one. You can get that using a correlated subquery:
select h.*,
(select h2.page_url
from hits h2
where h2.visit_id = h.visit_id and h2.page_next = h.page_url and
h2.timestamp < h.timestamp
order by timestamp desc
limit 1
) as page_prev
from hits h
Doing the update is a bit tricky in MySQL, because you are not able to directly use the updated table in the update. But, the following trick should work:
update hits
set page_prev = (select page_url
from (select page_url
from hits h2
where h2.visit_id = hits.visit_id and
h2.page_next = hits.page_url and
h2.timestamp < hits.timestamp
order by timestamp desc
limit 1
) h3
)
The trick works because MySQL materializes views, so it actually creates a "temporary table" containing the necessary information for the update.

Related

Query to find entries and transpose

I've got a machine log available in an SQL table. I can do a bit in SQL, but I'm not good enough to process the following:
In the data column there are entries containing "RUNPGM: Recipe name" and "RUNBRKPGM: Recipe name"
What I want is a view containing 4 columns:
TimeStamp RUNPGM
TimeStamp RUNBRKPGM
Recipe Name
Time Difference in seconds
There is a bit of a catch:
Sometimes the machine logs an empty RUNBRKPGM that should be ignored
The RUNBRKPGM is sometimes logged with an error message. This entry should also be ignored.
It's always the RUNBRKPGM entry with just the recipe name that's the actual end of the recipe.
NOTE: I understand this is not a full/complete answer, but with info available in question as of now, I believe it at least helps give a starting point since this is too complicated (and formatted) to put in the comments:
If Recipe is everything in the DATA field except the 'RUNPGM = ' part you can do somethign similar to this:
SELECT
-- will give you a col for TimeStamp for records with RUNPGM
CASE WHEN DATA LIKE 'RUNPGM%' THEN TS ELSE '' END AS RUNPGM_TimeStamp,
-- will give you a col for TimeStamp for records with RUNBRKPGM
CASE WHEN DATA LIKE 'RUNBRKPGM%' THEN TS ELSE '' END AS RUNBRKPGM_TimeStamp,
-- will give you everything after the RUNPGM = (which I think is the recipe you are referring to)
CASE WHEN DATA LIKE 'RUNPGM%' THEN REPLACE(DATA, 'RUNPGM = ', '' AS RUNPGM_Recipe,
-- will give you everything after the RUNBRKPGM = (which I think is the recipe you are referring to)
CASE WHEN DATA LIKE 'RUNBRKPGM:%' THEN REPLACE(DATA, 'RUNBRKPGM = ', '' AS RUNPGM_Recipe
FROM TableName
Im not sure what columns you want to get the Time Difference on though so I dont have that column in here.
Then if you need to do additional logic/formatting on the columns once they are separated you can put the above in a sub select.
As a first swing, I'd try the following:
Create a view that uses string splitting to break the DATA column into a its parts (e.g. RunType and RecipeName)
Create a simple select that outputs the recipe name and tstamp where the runtype is RUNPGM.
Then add an OUTER APPLY:
Essentially, joining onto itself.
SELECT
t1.RecipeName,
t1.TimeStamp AS Start,
t2.TimeStamp AS Stop
--date func to get run time, pseudo DATEDIFF(xx,t1.TimeStamp, t2.TimeStamp) as RunTime
FROM newView t1
OUTER APPLY ( SELECT TOP ( 1 ) *
FROM newView x
WHERE x.RecipeName = t1.RecipeName
AND RunType = 'RUNBRKPGM'
ORDER BY ID DESC ) t2
WHERE t1.RunType = 'RUNPGM';

SQL: user variable increment for each rows

EDIT : my question is not clear, so I've reformulated it here : Order sql result by occurrence of a set of keywords in a string
I'm improving my search system for my website. I'm trying to use and increment variables in sql request, like that...
SET #titlematch = 0;
SELECT *,
CASE
when title like '%apple%' then (SET #titlematch = #titlematch+1)
when title like '%orange%' then (SET #titlematch = #titlematch+1)
when title like '%other_keyword_searched%' then (SET #titlematch = #titlematch+1)
(...)
END,
(...)
FROM pages
(...)
ORDER by #titlematch desc
In fact, titlematch should be incremented each time that a keyword is in the title. If there's "apple" and "orange" in the title, titlematch should be equal to 2.
But actually, it doesn't work...
(sorry for my english)
I think it fails because it must handle all the data,if title like someWordYouDontAcccountFor it will fail.You must account for all possible cases or use else.
In response to your comment (Yes, always), I rewrite your query in this way:
SELECT *, (select count(*) from pages p2 where p1.field_date < p2.field_date) as pos
(...)
FROM pages p1
(...)
ORDER by (select count(*) from pages p2 where p1.field_date < p2.field_date) desc
In this way you count every rows before the actual (I've based my count on ipotetic field_date but if you want you can change your condition), so you have an incremental value for each row, and finally, I add this condition in order by clause.
Tell me if it's OK

Getting a row's position inside a MySQL table

I have a table where I store the standings data of a racing championship. The problem is - I don't actually store the driver's position, but I just store the number of points along with other data (number of wins, etc.) and then let MySQL sort it for me. This usually works fine, but what if I want to know a driver's position in a certain season? I could go with the following code:
SELECT l.driver, #curRow := #curRow + 1 AS position
FROM driverStandings l
JOIN (SELECT #curRow := 0) r
WHERE l.season = 1
ORDER BY l.points DESC, l.racesWon DESC
However, this would return a list of every driver and his/her position in season 1. If I just wanted to know a driver's (e.g. "Vettel") position, what could I do? I've tried everything I could think of, to no avail.
SELECT COUNT(v.id) + 1
FROM driverStandings d
LEFT JOIN driverStandings v
ON d.points > v.points
OR (d.points = v.points AND d.racesWon > v.racesWon)
WHERE v.id = ?
If you want, you can GROUP BY instead of filtering on v.id (just remember to add it to the SELECT list in order that you can identify each record though).
Do a select count where points are greater than that driver's points. This would be easiest in a second query, but there is that chance of a race condition (no pun intended).
select (count(*) + 1) as position from driverStandings l where l.points > :driverPoints
you really ought to store the position explicitly as mentioned in the comment to your original post. it will make all of the code surrounding this problem cleaner.
it should be possible to fill the values so the new driver position field is filled with the current row as in your example using an inert...select
however you could also make a get the same info inefficiently using a sub query

Is there a way to search mySQL rows from bottom up and change results based on paramaters?

Is there a way to convert the selected content of 0 or 1 to no or yes and search from bottom of table up?
UPDATE #__comprofiler
SET cb_trainingpass = ( SELECT c_passed
FROM #__quiz_r_student_quiz
WHERE #__quiz_r_student_quiz.c_student_id = #__comprofiler.user_id)
WHERE EXISTS
( SELECT c_passed
FROM #__quiz_r_student_quiz
WHERE #__quiz_r_student_quiz.c_student_id = #__comprofiler.user_id);
As users take their test, they get a result of 0 = not-passed, or 1 = passed. I am sending this to the field cb_trainingpass and would like it to be yes (for passed) or no instead. Also, users take the test multiple times and their newest results is what I am trying to pull, unfortunately this query pulls the one at the top or the first result, never finding the newest.
try something like
UPDATE #__comprofiler
SET cb_trainingpass = ( SELECT if(c_passed=1,'yes','no')
FROM #__quiz_r_student_quiz
WHERE #__quiz_r_student_quiz.c_student_id = #__comprofiler.user_id
order by #__quiz_r_student_quiz.YOURDATEFIELD desc)
WHERE EXISTS
( SELECT c_passed
FROM #__quiz_r_student_quiz
WHERE #__quiz_r_student_quiz.c_student_id = #__comprofiler.user_id);

Mysql: pulling from table

I am having some trouble putting a query together. I need to show images pulled in the order of if they are in the "editorial" section then if they have an order to be displayed in it will show the editorial image first but if its not ordered in that section it would just default and pull the regular image that is ordered already (which may not be a editorial type image but is a preferred one if nothing else is available). What I have now is the query below BUT that doesn't pull the editorial ranked images first but rather the "ordered_by' seems to take precedence.
SELECT i.img_name, a.artist_path_name, a.artist_dir, a.artist_name, ck.catKey_id
FROM images AS i JOIN artists AS a USING (artist_id)
JOIN img_cat_table AS imc USING ( img_id )
JOIN catkeys AS ck USING (catKey_id)
WHERE site = 'editorial' AND editorial_order = 1 OR ordered_by = 1 GROUP BY artist_name ORDER BY ed_banner
Its probably something silly that I am missing -- any and all help is appreciated.
Try something like:
...
ORDER BY CASE WHEN site = 'editorial' AND editorial_order = 1 THEN 1 ELSE 2 END,
ed_banner
or the same idea in a simpler way
ORDER BY (site = 'editorial' AND editorial_order = 1) DESC, ed_banner
It simply utilizes the order of FALSE, TRUE.
You should remove the respective conditions from the WHERE clause.