Need to fetch rows from MySQL - mysql

I have records in one of the column of MySQL DB like :
ID Tax
1 GST + PST + ABC
2 PST + GST + ABC
3 XYZ
4 PST + ABC + GST
These are stored as varchar in DB. Through my code I need to fetch records from DB that matches condition like tax = "GST + PST + ABC"
Currently I am getting only first record due to query:
Select * from table where taxes = "GST + PST + ABC";
But I want to fetch all records from DB in which above 3 names ( GST, PST, ABC) will occur irrespective of their positions.
So, I need records if I apply above condition:
GST + PST + ABC
PST + GST + ABC
PST + ABC + GST
I am using MySQL DB, please let me know is there any function through which I can achieve above results based on my condition

I would suggest something like this:
where taxes like '%GST%' and
taxes like '%PST%' and
taxes like '%ABC%' and
length(taxes) = 15;
This tests the length if you want exactly those three codes. You can also test the number of +:
where taxes like '%+%+%' and taxes not like '%+%+%+%'
Or if you want those codes and no others, then leave those conditions out.
This assumes that the names are non-overlapping (so there is no tax called "GS" or "ST"). If that is possibility:
where concat(' ', taxes, ' ') like '% GST %' and
concat(' ', taxes, ' ') like '% PST %' and
concat(' ', taxes, ' ') like '% ABC %';

You can use OR
SELECT * FROM TABLE WHERE TAXES = "GST + PST + ABC"
OR TAXES = "GST + ABC + PST"
OR TAXES = "PST + GST + ABC"
OR TAXES = "PST + ABC + GST"
OR TAXES = "ABC + GST + PST"
OR TAXES = "ABC + PST + ABC"
It's a pretty small list of things it could be, so I don't see a reason to get tricky with dynamically making complex SQL.
If data could be in other formats and you want to match like: "GST + ABC + PST + ZZZ" then we could do some work using LIKE AND %

I would use
WHERE NAME REGEXP "GST"
AND NAME REGEXP "PST"
AND NAME REGEXP "ABC"
Having said that, this sounds like a case where your data model isn't normalized enough. That is, you should be storing each tax-type in a separate row which will make MySQL operations a lot easier(just like in this case). It's not a good practice to store data in the form you have. I would attempt to store it this way:
ID ID-sub TAX
-- ------ ---
1 1 GST
1 2 PST
1 3 ABC
2 1 PST
2 2 GST
ID-sub may not be needed at all.

Related

Computed Column with relationships

I have a table, MapLocation, which has a column and two relationships with tables that have a field that really need to be displayed as a single concatenated value. I was thinking this was a perfect case for a computed column, but not sure how to go about it.
MapLocation MaoNo Section
_____________________ _____________________ _____________________
MapNoId MapNoId SectionId
SectionId MapNumber (int) Section (int)
Identifier (nvarchar)
LocationName (nvarchar)
LocationName = "MapNUmber - SectionNumber - Identifier"
ex: 20 - 03 - SW4
How would I write that? I haven't done much with computed columns or concatenating in SQL.
Edit:
I need an actual computed column that is automatically updated, im looking for the formula. Or is this more of a function/trigger? Its possible, I certainly barely know what I'm doing. The idea is that I dont want to have to do two more server calls and concatenate these values client side.
You would use something like this to get the value:
select cast(n.MapNumber as nvarchar(10)) + ' - ' -- cast the MapNumber
+ cast(s.SectionId as nvarchar(10)) + ' - ' -- cast the SectionId
+ l.Identifier
from MapLocation l
left join MaoNo n
on l.MapNoId = n.MapNoId
left join Section s
on l.SectionId = s.SectionId
Then if you need to perform an UPDATE:
update l
set l.LocationName = (cast(n.MapNumber as nvarchar(10)) + ' - '
+ cast(s.SectionId as nvarchar(10)) + ' - '
+ l.Identifier)
from MapLocation l
left join MaoNo n
on l.MapNoId = n.MapNoId
left join Section s
on l.SectionId = s.SectionId
Edit #1 - you can use a TRIGGER:
CREATE TRIGGER trig_LocationName
ON MapLocation
AFTER INSERT
AS
Begin
update MapLocation
set LocationName = (cast(n.MapNumber as nvarchar(10)) + ' - '
+ cast(s.SectionId as nvarchar(10)) + ' - '
+ i.Identifier)
from Inserted i
left join MaoNo n
on i.MapNoId = n.MapNoId
left join Section s
on i.SectionId = s.SectionId
where MapLocation.MapNoId = i.MapNoId -- fields here to make sure you update the correct record
End

Totalling based on expression field

In reporting services, I have used
=IIf(Fields!Weekday.Value="Su"
or Fields!Weekday.Value="Sa"
or Len(Fields!HOLIDAY.Value)>0,
(Fields!GENERAL.Value
+ Fields!LAUNCH.Value
+ Fields!SHIFT.Value
+ Fields!OCESAWE.Value
+ Fields!OCESAWD.Value
+ Fields!WEPHWORK.Value
+ Fields!OCREMWE.Value
+ Fields!OCREMWD.Value) * 1.5,
(Fields!GENERAL.Value
+ Fields!LAUNCH.Value
+ Fields!SHIFT.Value
+ Fields!OCESAWE.Value
+ Fields!OCESAWD.Value
+ Fields!WEPHWORK.Value
+ Fields!OCREMWE.Value
+ Fields!OCREMWD.Value)
)
To get a columnn called "Total Weighted" and this column have several rows.
1. ID Total Weighted
2. 111 21
3. 121 49
How can I get the total of the "Total Weighted?
Create a calculated field in your dataset, and use the formula you provided as the value of that field. Now you can refer to that field elsewhere as if it came from your database.
So then you'd use an expression like =SUM(Fields!TotalWeighted.Value) in your tablix.

MSSQL to MYSQL using CASE WHEN THEN SUBSTRING & CHARINDEX

I am having some real difficulty converting the below MSSQL statement to produce the same results in MYSQL.
The MSSQL query is as follows:
SELECT Radius_AdslUser.Password, Radius_AdslIp.IpAdd, Route =
CASE WHEN Radius_AdslIP.Route IS NULL
THEN NULL
WHEN Radius_AdslIp.TotalIp = 8
THEN Radius_AdslIP.Ipadd + '/29 ' + SUBSTRING(Radius_AdslIp.Route, 10, Charindex(' ', Radius_AdslIp.Route) - 10) + ' 1'
WHEN Radius_AdslIp.TotalIp = 4
THEN Radius_AdslIP.Ipadd + '/30 ' + SUBSTRING(Radius_AdslIp.Route, 10, Charindex(' ', Radius_AdslIp.Route) - 10) + ' 1'
WHEN Radius_AdslIp.TotalIp = 16
THEN Radius_AdslIP.Ipadd + '/28 ' + SUBSTRING(Radius_AdslIp.Route, 10, Charindex(' ', Radius_AdslIp.Route) - 10) + ' 1'
END, AVPair =
CASE WHEN Radius_AdslUser.bandcap IS NULL
THEN NULL
ELSE 'throttle=' + Radius_AdslUser.bandcap
END, Radius_AdslIp.Subnet
FROM Radius_AdslUser,Radius_AdslIp
WHERE Username = 'username#test.tld'
AND Suspended = 0
AND Radius_AdslUser.IpAddId = Radius_AdslIp.IpAddId
Which produces the following result:
Password IpAdd Route AVPair Subnet
kmbjdatr 10.0.0.1 10.0.0.1/29 10.0.0.0 1 NULL 255.255.255.255
The format of the tables are as follows:
Radius_AdslIp
IpAddId IpAdd Subnet TotalIp UsableIp Route TypeId
944 10.0.0.1 255.255.255.255 8 6 ip:route=10.0.0.0 255.255.255.248 4
Radius_AdslUser
Username Password IpAddId
username#test.tld kmbjdatr 944
I have substituted CHARINDEX for LOCATE and have used CONCAT but am not having much luck.
For example:
WHEN Radius_AdslIp.TotalIp = 8 THEN Radius_AdslIp.Ipadd = CONCAT(Radius_AdslIp.Ipadd, '/29 ')
The table formats in MYSQL are identical.
Any help would be greatly appreciated.
Seems like you are not applying the CONCAT function correctly. Basically, a SQL Server expression like this:
column_name + 'constant string' + function_call() + #variable
would look like this in MySQL:
CONCAT(column_name, 'constant string', function_call(), #variable)
The particular wrong part in your excerpt seems to be Radius_AdslIp.Ipadd = (the one before CONCAT). Not sure what you meant by that, but in any event it's just not needed there.

I need help finding the average number out of 60 columns, where the columns number does not equal 0

We have 2500 products on our site, ranked between 60 different categories. Our DB scheme is 61 columns, labled "product_id", and then the categories: "category_1", "category_2"... "category_60", and 2500 rows, one for each product. If a product is not ranked in a specific cateogry, that corresponding field is marked "0". If it is ranked, the field is an INT with whatever rank it is: "1" is 1st, "2" is second, etc.
Usually products are only ranked in 2-3 categories, so there are 57+ columns with a "0" in the field. My current query is:
mysql_query("SELECT AVG(category_1 + category_2 + category_3 + category_4 + category_5 + category_6 + category_7 + category_8 + category_9 + category_10 + category_11 + category_12 + category_13 + category_14 + category_15 + category_16 + category_17 + category_18 + category_19 + category_20 + category_21 + category_22 + category_23 + category_24 + category_25 + category_26 + category_27 + category_28 + category_29 + category_30 + category_31 + category_32 + category_33 + category_34 + category_35 + category_36 + category_37 + category_38 + category_39 + category_40 + category_41 + category_42 + category_43 + category_44 + category_45 + category_46 + category_47 + category_48 + category_49 + category_50 + category_51 + category_52 + category_53 + category_54 + category_55 + category_56 + category_57 + category_58 + category_59 + category_60) as 'cat_avg' FROM products.rankings WHERE product_id = '$product_id'");
With this, I'm just getting the sum of the columns, not the AVG. Maybe this has something to do with selecting rows instead of columns, I'm not sure. I tried SUM as well, instead of AVG, same thing.
I'm not really sure where to go from here. What i would like is the Average ranking across all columns for one product, where the column doesn't equal 0. So if a product_id 123 is ranked 7, 9 and 11, and then the other 57 columns are 0, the average returned would be 9 ((7+9+11)/3), not .45 ((7+9+11+0+0+0....+0))/60)
Note: I did not design this DB, I'm sure there is a better way to design it, but at this point it's too deeply integrated to change up quickly.
This may be a lot of stress on the query, but I don't know many other ways to do this, given the schema you have to work with.
One option is to sub-query the columns and union them, where the given columns are not 0:
SELECT AVG(
SELECT *
FROM (
SELECT category_1 AS category FROM table
UNION
SELECT category_2 AS category FROM table
UNION
...
) cats
WHERE category <> 0
)
FROM products.rankings
WHERE product_id = '$product_id'
It probably makes more sense to do this math within the page (assuming PHP given the query decorations) and on a per-row basis. Doing the above will put a lot of strain on the server depending the number of rows we're talking.
Restructured the whole DB... wasn't as bad as I though, just did a bunch of MySQL queries/updates that got me what I needed. Strained the server for a few hours, but it was well worth it in the end.

Questions on SQL Server 2008 Full-Text Search

I have some questions about SQL 2K8 integrated full-text search.
Say I have the following tables:
Car with columns: id (int - pk), makeid (fk), description (nvarchar), year (int), features (int - bitwise value - 32 features only)
CarMake with columns: id (int - pk), mfgname (nvarchar)
CarFeatures with columns: id (int - 1, 2, 4, 8, etc.), featurename (nvarchar)
If someone searches "red honda civic 2002 4 doors", how would I parse the input string so that I could also search in the "CarMake" and "CarFeatures" tables?
Trying to parse search criteria like that will be a pain. A possible alternate solution would be to create a view that creates a long description of the car and create a full text index on that. So that view might look like:
Create View dbo.CarData
WITH SCHEMABINDING
As
Select dbo.Cars.Id
, dbo.CarMake.Manufactuer
+ ' ' + dbo.Cars.[Year]
+ Coalesce(' ' + dbo.Cars.Description,'')
+ ' ' + Case When Features & 1 <> 0 Then (Select Name From dbo.CarFeature Where Id = 1) Else '' End
+ ' ' + Case When Features & 2 <> 0 Then (Select Name From dbo.CarFeature Where Id = 2) Else '' End
+ ' ' + Case When Features & 4 <> 0 Then (Select Name From dbo.CarFeature Where Id = 4) Else '' End
+ ' ' + Case When Features & 8 <> 0 Then (Select Name From dbo.CarFeature Where Id = 8) Else '' End
+ ' ' + Case When Features & 16 <> 0 Then (Select Name From dbo.CarFeature Where Id = 16) Else '' End As Description
From dbo.Cars
Join dbo.CarMake
On CarMake.Id = Cars.MakeId
With a fulltext index on that view, then you might be able to take your search criteria and do:
Select ...
From CarData
Where Contains(Description, Replace('red honda civic 2002 4 doors', ' ', ' AND '))
Now, this is far from perfect. For example, it will result in '...4 AND doors' and thus find car models in 2004 with 2 doors or 4WD and 2 doors. In addition, I did not see color in your schema so I'm not sure how that would get into the mix.
It would obviously be substantially simpler to force the user to break up the search criteria into its constituent pieces instead of trying to implement a Google-like search. Thus, you would restrict the user to selecting the color from a drop list, selecting the make from another drop list and so on. If you did this, then you wouldn't need the above mentioned View and could instead query against the columns in the tables.
Btw, the features column being a bitwise value makes searches more of a pain as you will need to do a bitwise AND operation on each value to determine if it has the feature in question. It would be better to break out the Feature to Car mapping into a separate table.