ORDER BY first OR condition true - mysql

I have the folloing table in a MySQL 5.6+ database
+----+-------+-------+--------------+--------------+
| id | mood1 | mood2 | mood1_visual | mood2_visual |
+----+-------+-------+--------------+--------------+
| 1 | 5 | 7 | 5c | 7a |
| 2 | 5 | 7 | 5b | 7b |
| 3 | 5 | 7 | 5c | 7d |
| 4 | 5 | 8 | 5a | 8a |
| 5 | 5 | 7 | 5c | 7a |
| 6 | 5 | 8 | 5b | 8a |
+----+-------+-------+--------------+--------------+
I need to select rows where
(`mood1_visual`='5c' AND `mood2_visual`='7a') OR
(`mood1`=5 AND `mood2`=7 AND (`mood1_visual`<>'5c' OR `mood2_visual`<>'7a'))
In the example above those would be the rows 1,2,3 and 5. However I need them sorted with the ones that match the first part of the WHERE clause before the others, i.e. I need them sorted 1,5,2,3, because row 1 and row 5 satisfy the first part of the WHERE clause
(`mood1_visual`='5c' AND `mood2_visual`='7a')
How do I tell that in the ORDER BY clause? Is there anything like
ORDER BY THE ONES THAT MATCH CONDITION FIRST THEN THE OTHERS ?
Please note that 5,1,2,3 or 1,5,3,2 or 5,1,3,2 are all valid sortings for my needs, just in case that made the solution easier.

MySQL can order by arbitrary expressions, e.g.
ORDER BY (foo = bar)
The boolean result of that will be typecast to an integer 0 or 1, so if you want all of the "equal" values first (1), then
ORDER BY (foo = bar) DESC
and if you want all of the false (0) values first, then
ORDER BY (foo = bar) ASC

What if you use CASE expression with ORDER BY like
ORDER BY
CASE
WHEN (`mood1_visual`='5c' AND `mood2_visual`='7a') THEN id
END

Related

How to find max of mysql varchar column

i have a table like this with a var char field reference_number
actually i need to get the max of number in that field
<<student>>
|`id` | `reference_number`(varchar(25))
--------------------------
| 1 | L250
| 2 | SP521
| 3 | S120
| 4 | SP500
| 5 | S122
the desired result is 521 because if we are avoiding the non numeric value then it will come like this
|`id` | `reference_number`
--------------------------
| 1 | 250
| 2 | 521
| 3 | 120
| 4 | 500
| 5 | 122
how to get the the value 521 from the table
I assume you have extracted 'reference_number' as shown in the second snippet from the first snippet. if so, try :::
select max(cast (reference_number as int)) from student
In order to get the number 521 (and all the numbers from the reference_number column) you could try:
SELECT *
FROM yourtable
WHERE reference_number REGEXP '^[0-9]+$';
And then you can add an order by statement.

Select statement inside SSRS textbox

I am trying to assign values to textboxes in SSRS but am running into a bit of trouble.
My dataset "dsStepInfo" groups and sums a number of rows together based on "ID", query below.
SELECT ID, SUM(Target) AS Target, SUM(Actual) AS Actual
FROM tblStepComplete
WHERE (CompleteID = #ParamID)
GROUP BY ID
And returns:
ID Target Actual
-------------------------------
| 10 | 44418 | 44418 |
-------------------------------
| 12 | 13193 | 13123 |
-------------------------------
| 22 | 1411 | 1411 |
-------------------------------
| 50 | 160 | 80 |
-------------------------------
| 52 | 68 | 34 |
-------------------------------
| 101 | 12120 | 12119 |
-------------------------------
| 105 | 875 | 868 |
-------------------------------
| 140 | 40 | 40 |
-------------------------------
| 560 | 2985 | 3418 |
-------------------------------
I want to assign cells in the grid in the picture to a certain ID. The Cell for tank 110 would always be the Target of ID=50 and Actual of ID=50 for example. Many of the IDs returned aren't going to be populated in the table, just the 10 displayed in this table. Is there any way to perform a SELECT, or equivalent in the textbox as an expression to get these specific values from the dataset?
You can use the Lookup function.
This should get the ID #50 and output its Target:
=Lookup(50, Fields!ID.Value, Fields!Target.Value, "DSStepInfo")
I think if it were me I'd just use a Case statement, something like
SELECT
Case [ID]
WHEN 10 Then 'Tank 50'
WHEN 12 Then 'Tank 120'
When 22 Then 'Tank 130'
WHEN 50 Then 'Tank 140'
When 52 Then 'Tank 150'
End As TankNo
,SUM([Target]) As Target
,SUM([Actual]) As Actual
FROM tblStepComplete
WHERE (CompleteID = #ParamID)
Group By [ID]
And then build your report using the values presented. Better would be an additional table that had the Tank names linked to the IDs you are pulling, but if you don't have that then the Case statement is fairly easy to maintain.

MySQL Count within an IF

+-------------+--------------+----------+-------+
| ticketRefNo | nameOnTicket | boughtBy | event |
+-------------+--------------+----------+-------+
| 38 | J XXXXXXXXX | 2 | 13 |
| 39 | C YYYYYYY | 1 | 13 |
| 40 | M ZZZZZZZZZZ | 3 | 14 |
| 41 | C AAAAAAA | 3 | 15 |
| 42 | D BBBBBB | 3 | 16 |
| 43 | A CCCCC | 3 | 17 |
+-------------+--------------+----------+-------+
+-------------+------------------+--------------+---------------------+--------+
| ticketRefNo | cardNo | cardHolder | exp | issuer |
+-------------+------------------+--------------+---------------------+--------+
| 38 | 4444111133332222 | J McKenny | 2016-01-01 00:00:00 | BOS |
| 39 | 4434111133332222 | C Dempsey | 2016-04-01 00:00:00 | BOS |
| 40 | 4244111133332222 | M Gunn-Davis | 2018-02-01 00:00:00 | RBS |
+-------------+------------------+--------------+---------------------+--------+
+-------------+-------------+----------+
| ticketRefNo | boxOfficeID | paidWith |
+-------------+-------------+----------+
| 41 | 1 | card |
| 42 | 2 | cash |
| 43 | 3 | chequ |
+-------------+-------------+----------+
I have a database with the data shown above. It represents a ticket-buying system. I would like to be able to see a list of tickets bought with the name of the event and either the boxOfficeID or the issuer of the debit card.
I have tried running the following code, to no avail.
SELECT t.ticketRefNo AS 'Reference', t.event AS 'Event',
IF(COUNT(SELECT * FROM Online WHERE t.ticketRefNo=o.ticketRefNo;) >= 1,
o.issuer, InPerson.boxOfficeID) AS 'Card Issuer or Box Office'
FROM Ticket AS t, InPerson, Online AS o
WHERE t.ticketRefNo=o.ticketRefNo;
Cheers in advance!
Some notes: the semicolon character isn't valid syntax; if you have a need to delimit the subquery, wrap it in parens. Escape column aliases like you'd escape any other identifier: use backticks, not single quotes. Single quotes are used around string literals.
Assuming that issuer in the Online table is NOT NULL, and assuming that ticketRefNo is unique in both the Online and InPerson tables, you could do something like this:
SELECT t.ticketRefNo AS `Reference`
, t.event AS `Event`
, IF(o.ticketRefNo IS NOT NULL,o.issuer,i.boxOfficeId)
AS `Card Issuer or Box Office`
FROM Ticket t
LEFT
JOIN InPerson i
ON i.ticketRefNo = t.ticketRefNo
LEFT
JOIN Online o
ON o.ticketRefNo = t.ticketRefNo
Use outer join operations to find matching rows in the InPerson and Online tables, and use a conditional test to see if you got a matching row from the Online table. A NULL will be returned if there wasn't a matching row found.
It's not a good idea to have one column JOINing to two different tables with some values in each of the two tables.
But here goes anyway:
( SELECT ... FROM Ticket t JOIN InPerson x USING(ticketRefNo) ... )
UNION ALL
( SELECT ... FROM Ticket t JOIN Online x USING(ticketRefNo) ... )
ORDER BY ...
The ALL assumes that InPerson and Online never have any overlapping ticketRefNos.
The ORDER BY an the end is in case you want to sort things, although I see no need for it in your attempted SELECT.
The two SELECTs must have the same number of columns.

MySQL using GROUP BY to group by multiple columns

I'd like to use GROUP BY multiple columns, I think it's best to start with an example:
SELECT
eventsviews.eventId,
showsActive.showId,
showsActive.venueId,
COUNT(*) AS count
FROM eventsviews
INNER JOIN events ON events.eventId = eventsviews.eventId
INNER JOIN showsActive ON showsActive.eventId = eventsviews.eventId
WHERE events.status = 1
GROUP BY showsActive.venueId, showsActive.showId, showsActive.eventId
ORDER BY count DESC
LIMIT 100;
Output:
| *eventId* | *showId* | *venueId* | *count* |
+-----------+----------+-----------+---------+
[...snip...]
| 95 | 92099 | 9770 | 32 |
| 95 | 105472 | 10702 | 32 |
| 3804 | 41225 | 8165 | 17 |
| 3804 | 41226 | 8165 | 17 |
| 923 | 2866 | 5451 | 14 |
| 923 | 20184 | 5930 | 14 |
[...snip...]
What I would like instead:
| *eventId* | *showId* | *venueId* | *count* |
+-----------+----------+-----------+---------+
| 95 | 92099 | 9770 | 32 |
| 3804 | 41226 | 8165 | 17 |
| 923 | 20184 | 5930 | 14 |
So, I want my data grouped by eventId, but only once for each showId and venueId ...
I actually have a SQL query that does that, but it has 8 subqueries and is as slow as a T-Ford ... And since this is executed on every page load, speeding things up looks like a good idea!
There are a few questions like this, and I've tried many different things, but I've been at this query for an hour and I can't seem to get it to work as I want :-(
Thanks!
You probably want either a min or a max on showid, and then not include it in the group by, I can't tell which because looking at your "prefered" resultset, you have both.
If you want your data grouped by eventId, group just by eventId and you'll get exactly the result you're looking for.
This is a MySQL feature (?) that it allows you to select non-aggregate columns, in which case it will return the first row available. In other DBMS it's achieved by DISTINCT ON, which is not available in MySQL.

Is there a query in MySQL that would allow variable group numbers and limits akin to this

I've checked out a few of the stackoverflow questions and there are similar questions, but didn't quite put my fingers on this one.
If you have a table like this:
uid cat_uid itm_uid
1 1 4
2 1 5
3 2 6
4 2 7
5 3 8
6 3 9
where the uid column in auto_incremented and the cat_uid references a
category of relevance to filter on and the itm_uid values are the one
we're seeking
I would like to get a result set that contains the following sample results:
array (
0 => array (1 => array(4,5)),
1 => array (2 => array(6,7)),
2 => array (3 => array(8,9))
)
An example issue is - select 2 records from each category (however many categories there may be) and make sure they are the last 2 entries by uid in those categories.
I'm not sure how to structure the question to allow an answer, and any hints on a method for the solution would be welcome!
EDIT:
This wasn't a very clear question, so let me extend the scenario to something more tangible.
I have a set of records being entered into categories and I would like to select, with as few queries as possible, the latest 2 records entered per category, so that when I list out the contents of those categories, I will have at least 2 records per category (assuming that there are 2 or more already in the database). A similar query was in place that selected the last 100 records and filtered them into categories, but for small numbers of categories with some being updated faster than others can lead to having the top 100 not consisting of members from every category, so to try to resolve that, I was looking for a way to select 2 records from each category (or N-records assuming it's the same per-category) and for those 2 records to be the last entered. A date field is available to sort on, but the itm_uid itself could be used to indicate inserted order.
SELECT cat_uid, itm_uid,
IF( #cat = cat_uid, #cat_row := #cat_row + 1, #cat_row := 0 ) AS cat_row,
#cat := cat_uid
FROM my_table
JOIN (SELECT #cat_row := 0, #cat := 0) AS init
HAVING cat_row < 2
ORDER BY cat_uid, uid DESC
You will have two extra columns in the results, just ignore them.
This is the logic:
We sort the table by cat_uid, uid descending, then we start from the top and give each row a "row number" (cat_row) we reset this row number to zero whenever cat_uid changes:
---------------------------------------
| uid | cat_uid | itm_uid | cat_row |
| 45 | 4 | 34 | 0 |
| 33 | 4 | 54 | 1 |
| 31 | 4 | 12 | 2 |
| 12 | 4 | 51 | 3 |
| 56 | 6 | 11 | 0 |
| 20 | 6 | 64 | 1 |
| 16 | 6 | 76 | 2 |
| ... | ... | ... | ... |
---------------------------------------
now if we keep only the rows that have cat_row < 2 we get the results we want:
---------------------------------------
| uid | cat_uid | itm_uid | cat_row |
| 45 | 4 | 34 | 0 |
| 33 | 4 | 54 | 1 |
| 56 | 6 | 11 | 0 |
| 20 | 6 | 64 | 1 |
| ... | ... | ... | ... |
---------------------------------------
This is called an adjacent tree model or a parent-child tree model. It's one of the simplier tree model where there is only 1 pointer or 1 leaf. You would solve your query with a recursion or using a Self Join. Sadly MySQL doesn't support recursive queries, maybe it's working with prepared statements. I want to suggest you an Self Join. With a Self Join you can get all the rows from the right side and the left side with a special condition.
select t1.cat_uid, t2.cat_uid, t1.itm_uid, t2.itm_uid From t1 Inner Join t2 On t1.cat_uid = t2.cat_uid