Trying to use mysql to exclude certain ones - mysql

I'm fairly new to mySQL. I have a table that is supposed to be mutually exclusive between fields labeled "b" or "s", but they aren't. Some fields in column tn have "b", and another field has "s" but they both have the same "tn". This is a data issue I'm waiting for someone to fix. In the meantime, I need to exclude from my "b" query, any items where "tn" would also be in the similar "s" query. My query just has the "b" ones in it, how do I compare against the "s" ones and exclude the crossover errors? Also, I want to exclude any "b" ones with a "tn" count over 2. I know they need to fix the data, but while I'm waiting the months that will take, I want to get a set of data to start with, that is clean. I need the returned row to include all columns shown.
The Table hardware_data looks like this:
tn hardware_item shelf slot port type model
12345678 abcdefg 1 1 1 b Model1
23456789 bcdefgh 1 2 3 b Model1
23456789 bcdefgh 1 2 3 s Model1
34567890 cdefghi 1 1 4 s Model1
12345678 abcdefg 1 1 4 b Model1
12345678 abcdefg 1 1 3 b Model1
45678901 defghij 1 1 2 b Model1
45678901 defghij 1 1 3 b Model1
So in the above data, I would use the following query:
select hardware_item, tn, shelf, slot, port
from accessInventory.hardware_data
WHERE model= 'Model1'
AND type = 'b'
AND CHAR_LENGTH(tn)>3
AND tn*1 = tn
LIMIT 100000;
And it returns this data set
tn hardware_item shelf slot port type model
45678901 defghij 1 1 2 b Model1
45678901 defghij 1 1 3 b Model1
23456789 bcdefgh 1 2 3 b Model1
12345678 abcdefg 1 1 4 b Model1
12345678 abcdefg 1 1 3 b Model1
12345678 abcdefg 1 1 1 b Model1
But I want it to exclude the ones with a duplicate count "tn" over 2 like 12345678 , and ones that cross-over with the "s" category, like 23456789. I don't even know where to start with the cross-over one, and my count over 3 exclusion isn't working because it's comparing the entire row returned and not just the "tn". Any help would be greatly appreciated.
I've googled it of course, but I'm not finding anything for the exclusion I need, and I haven't found this specific case for excluding ones where count of common row items exceeds a value.
Note, can't use "Group By" because it's valid to have 2 tn's matching in "b" category.

Related

How to get data with condition SQL QUERY

So first of all, I have 2 table. The first one is the categories
Id Name
------------
1 Interior
2 Eksterior
3 Display
then the secon table is history which the data is the task I've finished
Id category_name category_id date (month) User Id
---------------------------------------------------------------
001 Interior 1 3 1084
002 Eksterior 2 3 1084
003 Interior 1 4 1089
004 Eksterior 2 4 1085
005 Display 3 4 1085
and what I want is to get categories by month, user id and know which one already done and not done from history, like this
example the data in March with user id 1084 :
Id Name Status
---------------------------
1 Interior done
2 Eksterior done
3 Display not done
or like this :
Id Name Status
--------------------------
1 Interior 1
2 Eksterior 1
3 Display 0
if the category in history table exist, the status will be 1 for done and 0 for not done.
this is my query before :
SELECT c.id, c.category, c.id=h.category_id status FROM categories c, history h WHERE MONTH(h.created_at)
I keep retrieving the wrong result for my query. Please help me..
Seems like:
SELECT *
FROM
categories c
LEFT JOIN history h on h.category_id = c.id AND h."date (month)" = 3
..will get you towards what you want: there will be NULL in the row from history table, for category Display; you can use this "is or is not null" to create your done/not done column

Duplicate or unpredictable results in MySQL

I'm trying to join a few tables in MySQL. Our setup is a little unique so I try to explain as good as I can.
I have a table 'INVENTORY' that represents the current items on stock.
These items are stored in a table 'COMPONENT'
Components are being used in installations.
Every user can have multiple installations and the same component can be used in multiple installation as well.
To uniquely map a component to an installation, it can be assigned to a PRODUCT. a product as has a 1-1 relationship with an installation. A component is not directly related to an installation
To finally assign a product to a specific installation a mapping table COMPOMENT_PRODUCT is used.
Example:
A component is like a part, lets say a screw. This screw is used in a computer. The very same screw can be used on multiple computers. But each computer can only be used on one specific installation.
TABLE COMPOMENT_PRODUCT
COMPOMENT_ID PRODUCT_ID
1 1
1 2
2 1
2 2
So we have the components C1 and C2 relevant for two installations.
TABLE INVENTORY
COMPOMENT_ID INSTALLATION_ID ON_STOCK
1 1 5
1 2 2
What I want to achieve
Now, I want to retrieve the inventory state for all components. But, not every component has an inventory record. In these cases, the ON_STOCK value from the inventory shall be NULL
That means, for this example I'd expect the following results
COMPOMENT_ID PRODUCT_ID ON_STOCK
1 1 5
1 2 2
2 1 NULL
2 2 NULL
But executing this query:
SELECT DISTINCT
COMPONENT_PRODUCT.COMPONENT_ID,
COMPONENT_PRODUCT.PRODUCT_ID,
INVENTORY.ON_STOCK
FROM INVENTORY
RIGHT JOIN COMPONENT_PRODUCT ON COMPONENT_PRODUCT.COMPONENT_ID =
INVENTORY.COMPONENT_ID
returns the following resultset:
COMPONENT_ID PRODUCT_ID ON_STOCK
1 1 5
1 2 5
1 1 2
1 2 2
2 1 (null)
2 2 (null)
Now, my next thought was, "of course, this is how joins behave, okay I need to group the results". But the way SQL works, the aggregation is not entirely predictable. SO when I
GROUP BY COMPONENT_PRODUCT.COMPONENT_ID,COMPONENT_PRODUCT.PRODUCT_ID
I get this result:
COMPONENT_ID PRODUCT_ID ON_STOCK
1 1 5
1 2 5
2 1 (null)
2 2 (null)
I have prepared a Fiddle here: http://sqlfiddle.com/#!9/71ca87
What am I forgetting here? Thanks in advance for any pointers.
Try this query -
SELECT DISTINCT
COMPONENT_PRODUCT.COMPONENT_ID,
COMPONENT_PRODUCT.PRODUCT_ID,
INVENTORY.ON_STOCK
FROM INVENTORY
RIGHT JOIN COMPONENT_PRODUCT ON COMPONENT_PRODUCT.COMPONENT_ID =
INVENTORY.COMPONENT_ID
AND COMPONENT_PRODUCT.PRODUCT_ID = INVENTORY.INSTALLATION_ID

Perform action on selected columns depending on their name

I've got a huge table, containing three "selection"-columns and many "data"-columns.
ID Thing1 Thing2 Thing3 avgData1 avgData2 highestEtc
---- -------- -------- -------- ---------- ---------- ------------
1 1 2 2 321 654 999
2 2 1 1 123 456 11
3 2 1 1 987 789 77
4 2 1 1 765 567 11
In my queries, I'm now selecting all entries with "Thing1" = x, "Thing2" = y, "Thing3" = z (Those three columns are selection-criteria.)
The purpose of getting those lines is to perform an action on each of the following data-columns: If it starts with "avg", I want to calculate an average of the specific column on all selected entries. On another prefix I want to count which number appears the most.
Is there a way of letting the MySQL Database do all this for me? I need a SQL-Statement that calculates the averages of the columns automatically, and performs other actions too.
For example, let's say I'd select the criteria Thing1=2, Thing2=1 and Thing3=1. Is there a way of writing the statement so that it returns only ONE entry, with the calculated things?
Result
----------------- ----------------- ----
(123+987+765)/3 (456+789+567)/3 11
I heard that this should be possible, and that it is a bad method of NOT letting the database perform those actions directly. Unfortunately, I have no idea how to do it.
Try this:-
SELECT ID, AVG(avgData1) AS RESULT1, AVG(avgData2) AS RESULT2, highestEtc
FROM YOUR_TAB
WHERE Thing1 = 2
AND Thing2 = 1
AND Thing3 = 1
GROUP BY ID
HAVING COUNT(highestEtc) > 1;
Hope this helps you.

Microsoft access iff statement

I've been making an award system in ms access but trying to use the if statement for 2 distinct parameters, i.e. in one class top 3 students get a different amount from what the top 3 students of another class might get. All the data of all classes is in one table.
See:
Student ID Class ID Average Rank Awards
1111 Form4 77.79166667 2
1189 Form4 105 1
1222 Form4 73.41666667 3
1234 Form4 69.95833333 4
1235 Form 3 77.16666667 3
1236 Form 3 72.875 4
1258 Form 3 82.54166667 1
1333 Form 3 77.25 2
1367 Form 2 56.54545455 4
1445 Form 2 75.66666667 2
1447 Form 2 75.72727273 1
1465 Form 2 74.18181818 3
1523 Form 1 76.18181818 3
1542 Form 1 75.51515152 4
1552 Form 1 79.03030303 2
1555 Form 1 79.63636364 1
at the awards column when creating a query the build formula I use i.e. IIf([Rank]=1,1100) gives all student IDs ranked 1 an award of 1100 but I want only form 1 student IDs to get 1100 and the others ranked 1st with different award values please assist.
I think you want something like:
IIF([ClassID] <> "Form 1", IIf([Rank]=1,500), IIf([Rank]=1,1100))
Obviously, you will have to edit the award amount since you didn't specify what you were giving, but the logic should hold true.
If this gets a bit more complicated, you can write a function in VBA (in any code module in the 'modules' section), and use it in the query:
ExpressionName: evaluateAward(ClassID, Rank)
In the function, you can then use nested select case statements. This may be much better for readability.

Storing data in a link table

Supoose I have the following:
tbl_options
===========
id name
1 experience
2 languages
3 hourly_rate
tbl_option_attributes
=====================
id option_id name value
1 1 beginner 1
2 1 advanced 2
3 2 english 1
4 2 french 2
5 2 spanish 3
6 3 £10 p/h 10
7 3 £20 p/h 20
tbl_user_options
================
user_id option_id value
1 1 2
1 2 1
1 2 2
1 2 3
1 3 20
In the above example tbl_user_options stores option data for the user. We can store multiple entries for some options.
Now I wish to extend this, i.e. for "languages" I want the user to be able to specify their proficiency in a language (basic/intermediate/advanced). There will also be other fields that will have extended attributes.
So my question is, can these extended attributes be stored in the same table (tbl_user_options) or do I need to create more tables? Obviously if I put in a field "language_proficiency" it won't apply to the other fields. But this way I only have one user options table to manage. What do you think?
EDIT: This is what I propose
tbl_user_options
================
user_id option_id value lang_prof
1 1 2 null
1 2 1 2
1 2 2 3
1 2 3 3
1 3 20 null
My gut instinct would be to split the User/Language/Proficiency relationship out into its own tables. Even if you kept it in the same table with your other options, you'd need to write special code to handle the language case, so you might as well use a new table structure.
Unless your data model is in constant flux, I would rather have tbl_languages and tabl_user_languages tables to store those types of data:
tbl_languages
================
lang_id name
1 English
2 French
3 Spanish
tbl_user_languages
================
user_id lang_id proficiency hourly_rate
1 1 1 20
1 2 2 10
2 2 1 15
2 2 3 20
3 3 2 10
Designing a system that is "too generic" is a Turing tarpit trap for a relational SQL database. A document-based database is better suited to arbitrary key-value stores.
Excepting certain optimisations, your database model should match your domain model as closely as possible to minimise the object-relational impedance mismatch.
This design lets you display a sensible table of user language proficiencies and hourly rates with only two inner joins:
SELECT
ul.user_id,
u.name,
l.name,
ul.proficiency,
ul.hourly_rate
FROM tbl_user_languages ul
INNER JOIN tbl_languages l
ON l.lang_id = ul.lang_id
INNER JOIN tbl_users u
ON u.user_id = ul.user_id
ORDER BY
l.name, u.hour
Optionally you can split out a list of language proficiencies into a tbl_profiencies table, where 1 == Beginner, 2 == Advanced, 3 == Expert and join it onto tbl_user_languages.
i'm thinking it's a mistake to put "languages" as an option. while reading your text it seems to me that english is an option, and it might have an attribute from option_attributes.