MySQL Query - pass argument into same query - mysql

I would like to combine all issues that have same ID and show who is affected without showing all the people affected with the same issue (multiple lines).
SELECT
plugin_id as 'Plugin id',
cve as CVE,
cvss3_base_score as cvss3_base_score,
risk as Risk,
COUNT(DISTINCT(Host)) as 'Affected Unique Hosts',
Name,
plugin_family as 'Plugin Family',
last_seen as 'Last Seen',
vulnerability_state as 'Vulnerability State'
from tenable_network
GROUP BY plugin_id
ORDER BY plugin_id DESC
Fetch Assets Query
============
SELECT
role_id,
Host,
Name,
Synopsis,
Port,
Protocol,
OS,
FQDN
FROM tenable_network
WHERE plugin_id='90317'
GROUP BY Host
As you can see, I can group all roles that have plugin_id 90317 (issue)
Is there a simple way to pass the argument within the query?
Thanks

Related

Query returns results when running it individually, returns an ambiguous reference when I add it to a larger query

I am trying to write a query that summarizes vulnerabilities by host name, and includes information about that host. Query is running in Rapid7 InsightVM
The query that returns asset information runs successfully, except when I append that query to return vulnerability information it returns an ambiguous reference error for description. But the ip address, host_name, and asset_id values returns just fine.
I am just trying to combined them together to return that information. I feel like something obvious is missing.
This returns what I want from the asset table including the OS Description (Windows, RHEL, etc):
SELECT da.asset_id, da.host_name, da.ip_address, dos.description
FROM dim_asset da
JOIN dim_operating_system dos ON dos.operating_system_id = da.operating_system_id
JOIN fact_asset fa ON fa.asset_id = da.asset_id
GROUP BY da.asset_id, da.host_name, da.ip_address, dos.description
This returns an ambiguous reference for the description, it works for asset_id, host_name, and ip_address:
WITH remediations AS (
SELECT DISTINCT fr.solution_id AS ultimate_soln_id, summary, fix, estimate, riskscore, dshs.solution_id AS solution_id
FROM fact_remediation(10,'riskscore DESC') fr
JOIN dim_solution ds USING (solution_id)
JOIN dim_solution_highest_supercedence dshs ON (fr.solution_id = dshs.superceding_solution_id AND ds.solution_id = dshs.superceding_solution_id)
),
assets AS (
SELECT da.asset_id, da.host_name, da.ip_address, dos.description
FROM dim_asset da
JOIN dim_operating_system dos ON dos.operating_system_id = da.operating_system_id
JOIN fact_asset fa ON fa.asset_id = da.asset_id
GROUP BY da.asset_id, da.host_name, da.ip_address, dos.description
)
SELECT
csv(DISTINCT dv.title) AS "Vulnerability Title",
host_name AS "Asset Hostname", ip_address AS "Asset IP", description AS "OS",
round(sum(dv.riskscore)) AS "Asset Risk",
summary AS "Solution",
fix as "Fix"
FROM remediations r
JOIN dim_asset_vulnerability_solution dvs USING (solution_id)
JOIN dim_vulnerability dv USING (vulnerability_id)
JOIN assets USING (asset_id)
GROUP BY r.riskscore, host_name, ip_address, asset_id, summary, fix
ORDER BY "Asset Risk" DESC WITH remediations AS (
Most likely, dim_asset_vulnerability_solution or dim_vulnerability also have a description field. Just qualifying the selected fields with their intended source should resolve this problem.
...
a.host_name AS "Asset Hostname", a.ip_address AS "Asset IP", a.description AS "OS"
...
JOIN assets AS a USING (asset_id)
...
GROUP BY r.riskscore, a.host_name, a.ip_address, asset_id, summary, fix
Note: asset_id is not a problem because USING has some extra "magic" that merges the references joined by it.
Comment: Unless there are very specific reasons, GROUP BY should not be used as a substitute for SELECT DISTINCT (referring to the assets CTE in particular)

How to Select DISTINCT Name where Dealer_ID in a Table MYSQL, prevent duplicate records

I have a MySQL Table, and a table where I do the next Query:
Select Diferent Customer_Name in a Table where Customer_ID=CED130828MJ8.
The goal of that query is that only get a List on Customer_Name and Customer_ID.
Sometimes certains Customer_ID lacks of Customer_Name, (yep, I know about Unique KEY, but, thats not the ISSUE). So, cuz of this I do a CONCAT, IF Customer_Name is Empty, then Customer_Name = Customer_ID
Obiously ID_USER will change.
Thats the Query that I do:
SELECT DISTINCT(
IF(Dealer_Name<>'',
CONCAT(Dealer_Name, '*',Dealer_ID),
CONCAT(Dealer_ID, '*',Dealer_ID)
)
) AS cc FROM received_invoices
WHERE Customer_ID='CED130828MJ8'
GROUP BY (cc)
ORDER BY cc ASC";
And thats how It looks the result of that QUERY:
"BEST BUY LTD CO*BTB052YU96"
And Almost works, I mean almost, because It only choose one Customer_ID of the table, but If a Customer_ID has two ore more records, it Will print, two records.
Let me show you:
"GERARDO GARCIA RIVERA*GARG870805726"
"GERARDO GARSIA RIBERA*GARG870805726"
"JERARDO GARZIA RIVERA*GARG870805726"
"JUAN ANTONIO MUÑOZ*MUGJ540314TV4"
"GUAN ANTONIO MUNIOZ*MUGJ540314TV4"
"JUAN ANTOÑO MUÑIOS*MUGJ540314TV4"
"JUAN HANTOIO MUÑOC*MUGJ540314TV4"
BUT THAT I really Want instead of that is only Get 1 Record per Customer_ID, like:
"GERARDO GARCIA RIVERA*GARG870805726"
"JUAN ANTONIO MUÑOZ*MUGJ540314TV4"
What Do I missing?, what did you suggest?
Thanks in Advance
SQL sees concatenated strings as different:
"GERARDO GARCIA RIVERA*GARG870805726"
"GERARDO GARSIA RIBERA*GARG870805726"
"JERARDO GARZIA RIVERA*GARG870805726"
If you only want to see one entry per Customer_ID, you will also get one name, not all of them. If it does not matter which one will be displayed, then use min() on it:
select
if(Dealer_Name<>'',
concat(min(Dealer_Name), '*',Dealer_ID),
concat(Dealer_ID, '*',Dealer_ID)
)
as cc from received_invoices
where Customer_ID='CED130828MJ8'
group by Dealer_ID
order by cc asc";
Note, that grouping is now done by Dealer_ID, not full concatenated string.
Few observations:
DISTINCT is not a function. So you don't need to use parentheses around it.
DISTINCT with GROUP BY on same column/alias is not required.
Try the following instead:
SELECT
CONCAT(IF(MAX(Dealer_Name) <> '', MAX(Dealer_Name), Dealer_ID),
'*',
Dealer_ID
) AS cc
FROM received_invoices
WHERE Customer_ID = 'CED130828MJ8'
GROUP BY Dealer_ID
ORDER BY cc ASC
#Madhur Bhaiya.
Before All, Thanks for your Attention, Your great, As you Said, that is the answer:
SELECT
CONCAT(IF(MAX(Dealer_Name) <> '', MAX(Dealer_Name), Dealer_ID),
'*',
Dealer_ID
) AS cc
FROM received_invoices
WHERE Customer_ID = 'CED130828MJ8'
GROUP BY Dealer_ID
ORDER BY cc ASC
In my particular case, might be not in other people, when I do that query it throws me that Error: Error Code: 1055. Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'facturacion.facturas_recibidas.Emisor_Razon_Social' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
So I google about it, and I found that when this kind of error happens, I must DISABLE-ONLY-FULL-GROUP-BY.
And in order to do that I need to modify my /etc/mysql/my.cnf Cuz I have Ubuntu Linux I do it at this way:
sudo nano /etc/mysql/my.cnf
Add this to the end of the file
[mysqld]
sql_mode = "STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION" 4. For Restart the MySQL server and apply the changes: "sudo service mysql restart" THIS WILL DISABLE ONLY_FULL_GROUP_BY for ALL users.
Then Do the Query Again, and Voila!!, The Query Works ok!!!!.
So now I need to Modify the my.cnf file after installed mysql on every platform of my customers (Windows/Linux/MAC).
In order to avoid that Errors.

How to "remove duplicates" from a UNION query

I have two tables in MySQL: One called gtfsws_users which contains users for a system I'm developing and another called gtfsws_repository_users which contains roles for these users.
gtfsws_users has these fields: email, password, name, is_admin and enabled.
gtfsws_repository_users has: user_email, repository_id and role.
The role is an integer that defines privileges over a GTFS repository (public transportation data, not relevant for my problem).
One important thing is that every administrator accont (that is, every user that has the is_admin flag set as 1 in gtfsws_users) has full access to all repositories.
Now, only users registered in gtfsws_repository_users will have access to a specific repository defined there (unless they are administrators, of course). One user can have multiple repositories which him/her can access.
What I'm trying to do is to get all users with access to a specific repository (it doesn't matter which type of role the user has, I just want to know if they can access the repository or not). So I'm writing this SQL statement for getting them:
(
SELECT DISTINCT
gtfsws_users.email AS email,
gtfsws_users.name AS name,
gtfsws_users.is_admin AS is_admin,
gtfsws_users.enabled AS enabled,
gtfsws_repository_users.role AS role
FROM
gtfsws_users
INNER JOIN
gtfsws_repository_users
ON
gtfsws_users.email = gtfsws_repository_users.user_email
WHERE
gtfsws_repository_users.repository_id = '2'
)
UNION
(
SELECT
email,
name,
is_admin,
enabled,
null AS role
FROM
gtfsws_users
WHERE
is_admin = 1
)
Now, this works fine for users with access to different repositories. It also gets all administrators too.
The problem is when I have an administrator that is also registered in gtfsws_repository_users, because I get it duplicated.
So for example, it I have this in gtfsws_users:
('test#test.com', '*****', 'Real name', 1, 1)
And also the user is registered in gtfsws_repository_users as this:
('test#test.com', 2, 10)
When I do the SELECT in MySQL (using the UNION to add all administrators) I get:
('test#test.com', 'Real name', 1, 1, 10)
('test#test.com', 'Real name', 1, 1, NULL)
What I need to do is to filter that table to remove duplicates, that is getting only:
('test#test.com', 'Real name', 1, 1, NULL)
Yes, getting NULL as the role (since it will be ignored as the user is an administrator).
Does anybody have a clue on how to achieve that?
Thanks a lot.
EDIT: Ok, thanks to Katrin's suggestion, I'm getting some progress. I do get one row, but it's the one with the role number defined. Any way to preserve the one with the NULL role instead of the defined one?
Since aggregate functions ignore null values, you can convert null to a number that can be extracted as min or max.
Assuming all your roles are greater than 0:
SELECT email, name, is_admin, enabled, nullif(min(coalesce(role, 0)), 0) as role
from
((
SELECT DISTINCT
gtfsws_users.email AS email,
gtfsws_users.name AS name,
gtfsws_users.is_admin AS is_admin,
gtfsws_users.enabled AS enabled,
gtfsws_repository_users.role AS role
FROM
gtfsws_users
INNER JOIN
gtfsws_repository_users
ON
gtfsws_users.email = gtfsws_repository_users.user_email
WHERE
gtfsws_repository_users.repository_id = '2'
)
UNION
(
SELECT
email,
name,
is_admin,
enabled,
null AS role
FROM
gtfsws_users
WHERE
is_admin = 1
)) as Q
GROUP BY email, name, is_admin, enabled

Using a COUNT value in an expression getting..does not include specified expression as part of an aggregate function

I am trying to display a warning if a bike station gets to over 90% full or less than 10% full. When i run this query I get "you are trying to execute query that does not include the iif statment... as part of an aggregate function.
Bike_locations table - Bicycle_id and Locations_ID
Locations table - Locations_ID, No_of_Spaces, Location_Address
SELECT Locations.Location_Address, Count(Bike_Locations.Bicycle_ID) AS CountOfBicycle_ID,
IIf(((([CountOfBicycle_ID]/[LOCATIONS]![No_Of_Spaces])*100)>90),"This Station is nearly full.
Need to move some bicycles out of here",IIf(((([CountOfBicycle_ID]/[LOCATIONS]![No_Of_Spaces])*100)
<10),"This station is nearly empty. Need to move some bicycles here","")) AS Warnings
FROM Locations INNER JOIN Bike_Locations ON Locations.[LOCATIONS_ID] = Bike_Locations.[LOCATIONS_ID]
GROUP BY Locations.Location_Address;
Anyone got a scooby
When you use a GROUP BY, you should have the exact same fields in both your SELECT and GROUP BY statements, except for the aggregate function that should only be specified in the SELECT
The aggregate function in your case is the COUNT(*)
The fields you aggregate on are:
in the SELECT : Location_Address and Warnings
in the GROUP BY : Location_Address only
The error message is telling you that you don't have the same in both statements.
2 solutions:
Remove the Warnings from the SELECT statement
Add the Warnings to the GROUP BY statement
Note that in MS Access SQL, you can't (unfortunately) use in the GROUP BY, the Aliases specified in the SELECT. So you have to copy over the whole field, which would be the long iif in your case
Edit: better solution proposal:
I would radically change your approach as you'll go no where with all those nested iff
Create the following Query and Name it (for instance) Stations_Occupation
SELECT L.Locations_ID AS ID,
L.Location_Address AS Addr,
L.No_of_Spaces AS TotSpace,
BL.cnt AS OccSpace,
ROUND((BL.cnt/L.No_of_Spaces*100),0) AS OccPourc
FROM Locations L
LEFT JOIN
(
SELECT Locations_ID, COUNT(*) AS cnt
FROM Bike_Locations
GROUP BY LOCATIONS_ID
) AS BL ON L.Locations_ID = BL.Locations_ID
This query will probably be a lot helpfull in many parts of your application, and not only here, as it calculates the occupation % of each station
Some examples:
Get all stations with >90% occupation:
SELECT Addr
FROM Stations_Occupation
WHERE OccPourc > 90
Get all stations with <10% occupation:
SELECT Addr
FROM Stations_Occupation
WHERE OccPourc < 10
Get Occupation level of a specific station:
SELECT OccPourc
FROM Stations_Occupation
WHERE ID=specific_station_ID
Get number of bikes and max on a specific station:
SELECT OccSpace & "/" & TotSpace
FROM Stations_Occupation
WHERE ID=specific_station_ID

PGError: ERROR: column "inboxes.id" must appear in the GROUP BY clause or be used in an aggregate function

I have the following query to MySQL database:
SELECT inboxes.*
, count(inboxes.conv) AS times
, max(created_at) AS created_at
FROM `inboxes`
WHERE to_user = 2
OR account_id = 2
GROUP BY conv
ORDER BY id DESC
This query works on my localhost, but if I deploy it to Heroku, I'll get this error:
PGError: ERROR: column "inboxes.id" must appear in the GROUP BY clause or
be used in an aggregate function
You need to specify all fields in GROUP BY, which you wanna select, ie:
SELECT inboxes.id, count(inboxes.conv) AS times, max(created_at) as created_at FROMinboxesWHERE (to_user = 2 OR account_id = 2) GROUP BY inboxes.id, conv ORDER BY inboxes.id DESC
To avoid problems like this in the future, install postgres locally and develop your application with the same database it is using in production.
You should get rid of the inboxes.*. List each single parameter you need to fetch.
All parameters must be either grouped (GROUP BY) or used together with a group function(MAX, etc.).
I cannot tell you why its working on your localhost.