Best way to store configuration in MySQL - mysql

I have a scenario where i need to store configurations in mysql table having three columns namely VendorID,ServiceID and ModeID . Configuration for a vendor can be done with three overriding cases as follows.
One column VendorID having non-NULL value with ServiceID ,ModeID having NULL value.
VendorID,ServiceID,ModeID -- > 1,NULL,NULL
Two columns VendorID,ServiceID having non-NULL values with ModeID having NULL value.
VendorID,ServiceID,ModeID -- > 1,1,NULL
All three columns having non NULL values.
VendorID,ServiceID,ModeID -- > 1,1,1
When case 1,2,3 are defined and in the MySQL query WHERE clause vendorid,servideid and modeid are passed, then case 3 overrides case 2 and case 1.
When case 3 is not defined and case 1,2 are defined and in the MySQL query WHERE clause vendorid,servideid and modeid are passed, then case 2 overrides case 1.
When case 3 and case 2 are not defined and case 1 is defined and in the MySQL query WHERE clause vendorid,servideid and modeid are passed, then case 1 is returned.
Now my question is, how can i query the table to get the configuration returned when vendorid,servideid and modeid are passed in the query in one go without having to query 3 times separately.
Any other good approach for the above problem is also welcome.

You may want this:
where (VendorID, ServiceID, ModelID) = ($VendorID, $ServiceID, $ModelID) or
( (VendorID, ServiceID) = ($VendorID, $ServiceID) and ModelId is null) or
( VendorID = $VendorID and ServiceID is null and ModelId is null)
Alternatively you may want:
select t.*
from t
where VendorId = $VendorId and
(ServiceId = $ServiceId or ServiceId is null) and
(ModelId = $ModelId or ModelId is null)
order by ( ServiceId is not null ) desc,
( ModelId is not null ) desc
limit 1;
This returns one row with the best match.

Related

Create new unique value in column

I have a (MYSQL) table in the following format; assume the name of the table is mytable:
id
name
group
123
name1
1
124
name2
2
125
name3
1
126
name4
id is unique and auto-increments. name is a unique string, group is just an integer
I now want to assign name4 to a new group that does not exist yet, so the group for name4cannot be 1 or 2 in this example.
The result could,for example, be:
id
name
group
126
name4
3
At the moment I am sorting by group descending and just insert the highest number + 1 manually, but I was wondering if there was a better/quicker way to generate a new, unique value in a column. group has no other constraints, besides being an integer.
I am using the MySQL Workbench, so I can work with both SQL commands, as well as Workbench-specific options, if there are any.
If anything is unclear I'll gladly provide clarification.
In MySQL 8.0, you can get help with two window functions:
MAX, to retrieve the maximum "group" value
ROW_NUMBER, to retrieve the incremental value for each NULL existing in your table.
You can then sum up these two values and update your table where your "group" field is null.
WITH cte AS (
SELECT id, name, MAX(group_) OVER() + ROW_NUMBER() OVER(PARTITION BY group_ IS NULL ORDER BY name) AS new_group
FROM tab
)
UPDATE tab
INNER JOIN cte
ON tab.id = cte.id AND tab.name = cte.name
SET tab.group_ = cte.new_group
WHERE tab.group_ IS NULL;
Check the demo here.
In MySQL 5.X you can instead use a variable, initialized with your maximum "group" value, then updated incrementally inside the UPDATE statement, in the SET clause.
SET #maxgroup = NULL;
SELECT MAX(group_) INTO #maxgroup FROM tab;
UPDATE tab
SET group_ = (#maxgroup:= #maxgroup + 1)
WHERE group_ IS NULL;
ORDER BY id;
Check the demo here.

How do I search for a value in a column and also get count of the column in a single SQL query

I have a table of following structure in MySQL 5.7:
CREATE TABLE `post_like` (
`post_title_id` varchar(255) NOT NULL,
`user_name` varchar(50) NOT NULL,
PRIMARY KEY (`post_title_id`,`user_name`),
) ENGINE=InnoDB;
and I have the following data
post_title_id user_name
new-story mani27
new-story manipal
some-story manipal
I am trying to get the count of likes for a particular story and also if a particular user has liked the story in a function likeStatus(user_name, post_title_id)
Suppose likeStatus(mani27, new-story) would result in:
count status
2 1
I am using the following query right now and it works right:
SELECT COUNT(user_name) AS count,
COUNT(CASE WHEN `user_name` = ? THEN 1 ELSE null END) as status
FROM post_like WHERE post_title_id = ?
But this would execute the case function on all the rows in the table rather than searching the indexed column user_name.
I could use two different queries to get count and status of username liking a post, but that would take much more time than this. So, is there an optimised way to get this output?
I didn't check the query but this should give you an idea. Try Group By
SELECT COUNT(user_name) AS count,
COUNT(CASE WHEN `user_name` = ? THEN 1 ELSE null END) as status
FROM post_like GROUP BY post_title_id HAVING post_title_id=?
But this would execute the case function on all the rows in the table
rather than searching the indexed column user_name
When you group by basing on post_title_id= and then applying count functions on them, number of row searches for username can be reduced to rows in that group
Add your condition inside CASE not in WHERE, then make sure you use DISTINCT to avoid duplicates:
SELECT COUNT(DISTINCT user_name) AS count,
COUNT(CASE WHEN `user_name` = ? AND post_title_id = ? THEN 1 ELSE null END) as status
FROM post_like
You don't have to scan all the records to see if a user liked the post. Just use a subquery on the select list. That should use the primary key index.
Something like this should work
SELECT COUNT(*),
(SELECT COUNT(*) FROM post_like WHERE postid=? AND userid=?)
WHERE postid=?

MYSQL - COUNT() NULL Values

This has been racking my head. I've scoured the internet (including this place) and can't find a solution. So as a last resort I was hoping the good people of this forum might be able to help me out.
I have two tables:
TableA
Order_detailsID
OrderID
TitleID
Return_date
TableB
TitleID
Title_name
Quantity_in_stock
And would like to run a query that shows the remaining 'Quantity_in_stock'.
If the 'Return_date' is set to NULL then it means the item is currently out -- so I have been trying to use the count() function for the NULL values and subtract it from the 'Quantity_in_stock'.
This is the script I have so far:
DELIMITER //
CREATE PROCEDURE InStock()
BEGIN
Select TableB.TitleID,
TableB.Title_name,
TableB.Quantity_in_stock AS 'Total_Stock',
COUNT(TableA.return_date IS NULL) AS 'Rented_Out',
TableB.Quantity_in_stock - COUNT(TableA.return_date IS NULL) AS 'Remaining Stock'
From TableB
LEFT JOIN TableA
ON TableA.TitleID = TableB.TitleID
GROUP BY TableB.TitleID;
END//
This works if there is one of more of the TitleIDs at NULL, however if there are no values at NULL, then the Count() is still returning a value of 1 when it should be 0.
What am I doing wrong?
Instead of:
COUNT(TableA.return_date IS NULL)
use this:
SUM(CASE
WHEN TableA.TitleID IS NULL THEN 0
WHEN TableA.return_date IS NOT NULL THEN 0
ELSE 1
END)
The problem with the TableA.return_date IS NULL predicate is that it's true in two completely different situations:
When there is no matching record in TableA
When there is a matching record but TableA.return_date value of this exact record is NULL.
Using the CASE expression you can differentiate between these two cases.
I will like to mention a simple concept here, just keep counting the rows when that particular column is null.
select count(*) from table_name where column_name is null

SQL server: where clause for optional fields

Track Id is optional field in my application.
Case 1: If I pass valid track id, it should return the respective rows.
Case 2: If invalid track id is passed, no rows should be returned.
Case 3: If no track id passed, all rows should be returned
DECLARE #transaction_ID INT
SELECT #transaction_ID = Transaction_ID FROM myTable WHERE TRACK_ID= #Track_Id
My where condition is:
WHERE (#transaction_ID IS NULL OR myTable.Transaction_ID = #transaction_ID)
AND (amount<>0)
with the above condition 1 and 3 cases are working fine. but 2nd case got failed. When I passed invalid track id, all rows are getting returned. Please correct the query to handle the case 2. Thanks in advance.
Just continue to query #Track_ID as well:
WHERE (
(#transaction_ID IS NULL AND #Track_Id IS NULL) OR
myTable.Transaction_ID = #transaction_ID)
AND (amount<>0)
(The only situation where you want a NULL #Transaction_ID to make this WHERE clause succeed is case 3. In Case 2, a non-null #Track_Id was passed but #Transaction_ID will be NULL because no rows were returned, so that's the situation we're trying to deal with)
Try something like this
Where 1=(Case when #TrackId = 1 Or TRACK_ID= #Track_Id then 1 else 0 end )
When you want all the data then pass 1 ,
When want data as per TrackID pass #trackID value and
when you dont wnat the condition to be applied pass null

No results even by using EXISTS

I don't undersand why MySQL returns "MySQL did not produce a record" whereas I use EXISTS (I willingly chose a subquery which doesn't produce records) :
SELECT page_ID
FROM ranks_update
WHERE EXISTS (
SELECT *
FROM ranks_update
WHERE ranking_ID = 3
AND current_rank = 1
AND rating_time < '2012-08-05 02:57:59'
AND rating_time >= '2012-08-05 00:00:00'
GROUP BY page_ID
);
By definition EXISTS allows to get a result from a query which doesn't return any records. Until now I've always got NULL in such case.
It is returning that message because no records match. NULL is a value for a column. It is quite different from an empty return set.
If you have an aggregate function, then the empty set returns a NULL. So the following would return a NULL value:
select max(Page_ID)
and this would return 0:
select count(Page_ID)