Write MySQL query to get expected result for test table [duplicate] - mysql

This question already has an answer here:
Write a MySQL query to get required result
(1 answer)
Closed 2 years ago.
I am working with MySQL database.
Table contains data like:
id
uaid
attribute
value
time
risk factor
1
1234
File Path
Exist
16123
NONE
2
1234
File Path
Not Exist
16124
CRITICAL
3
1234
File Path
Exist
16125
NONE
the required result should be like below:
Attribute
Risk Factor
UAID
Failed Value
Present Value
File Path
CRITICAL
1234
Not Exist
Exist
Explanation:
we need to show data which have risk factor critical.
Failed Value = at the time (latest one) when risk factor is critical then value for that attribute represent as failed value
Present value = it is represented as current value for that attribute in database.
i have tried with the solution of two sql queries. one for taking getting rows which have risk factor equal to critical. and the second one for getting current value of each unique attribuite. and then some formatting of data from the both queries.
I am looking for solution which removes the extra overhead of data formatting according to requirement.
Schema table(id,uaid,attribute,value,time,risk_factor)

One option, using ROW_NUMBER:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY uaid, attribute
ORDER BY time DESC) rn
FROM yourTable
)
SELECT
attribute,
'CRITICAL' AS `Risk Factor`,
uaid,
MAX(CASE WHEN `risk factor` = 'CRITICAL' THEN value END) AS `Failed Value`,
MAX(CASE WHEN rn = 1 THEN value END) AS `Present Value`
FROM cte
GROUP BY
attribute,
uaid
HAVING
SUM(`risk factor` = 'CRITICAL') > 0;

Assuming that a group is a rowset with the same (uaid, attribute) values:
WITH cte AS (
SELECT DISTINCT
attribute,
'CRITICAL' `Risk Factor`,
uaid,
FIRST_VALUE(value) OVER (PARTITION BY uaid, attribute
ORDER BY `risk factor` = 'CRITICAL' DESC, `time` DESC) `Failed Value`,
FIRST_VALUE(value) OVER (PARTITION BY uaid, attribute
ORDER BY `time` DESC) `Present Value`,
SUM(`risk factor` = 'CRITICAL') OVER (PARTITION BY uaid, attribute) is_critical
FROM source_table
)
SELECT Attribute, `Risk Factor`, UAID, `Failed Value`, `Present Value`
FROM cte
WHERE is_critical;
fiddle

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.

Transform SQL SERVER table

i have this table
table with evaluators and evaluatees.
Every row of the table above is a relationship between two people(First row:person a evaluates person b, Second row person a evaluates person c and so on).
I want to trasform this table into looking like this
Wanted Output
So Each row will correspond one evaluator and each column will be people being evaluated by him. (Because some evaluators have less people to evaluate than others the remaining columns for someone who doesnt have that many evaluatees will be NULL.
Many thanks hope you can help me out
Since you have SQL Server tag so, i would use row_number() function with conditional aggregation :
select evalutor,
max(case when seq = 1 then evalutee end) as evalutee1,
max(case when seq = 2 then evalutee end) as evalutee2,
max(case when seq = 3 then evalutee end) as evalutee3
from (select t.*, row_number() over (partition by evalutor order by evalutee) as seq
from table t
) t
group by evalutor;

VĂ¡rios GROUP BY MySql

I'm trying to mount the sql that does the following query, in the TYPE field there are both type CUT and RELIANCE, but I need each of them to come in a column, but only I can now show it in each one in a line is possible to do so?
SELECT id_user, date_conclusion, type, COUNT (*)
FROM the
WHERE id_user = 8 and date_conclusion LIKE '2017-12%'
GROUP by date_conclusion, type
Assuming that only these two types exist. You do not need the extra type column then:
SELECT
id_user,
date_conclusion,
SUM(type = 'CORTE') AS 'CORTE',
SUM(type = 'RELIGACAO') AS 'RELIGACAO'
FROM
the
WHERE
id_user = 8 AND
date_conclusion LIKE '2017-12%'
GROUP BY
date_conclusion

remove duplicate rows in SQL Server Query

how could we remove or not displaying duplicate row with some conditional clause in sqlserver query, the case look like this one,
code decs
-------------------------
G-006 New
G-006 Re-Registration
how can we display just G-006 with Re-Registration Desc, i have tried with this query but no luck either
with x as (
select new_registration_no,category,rn = row_number()
over(PARTITION BY new_registration_no order by new_registration_no)
from equipment_registrations
)
select * from x
By using the same field in the PARTITION BY and ORDER BY clause, the rn field will always equal 1.
Assuming that new_registration_no = code and category = decs, you could change the ORDER BY field to be ORDER BY category DESC to get that result. However, that's a pretty arbitrary ORDER BY - you're just basing it on a random text value. I'm also not 100% sure how well the ROW_NUMBER() function works in a CTE.
A better solution might be something like:
SELECT *
FROM
(
SELECT
New_Registration_No,
Category,
ROW_NUMBER() OVER
(
PARTITION BY New_Registration_No
ORDER BY
CASE
WHEN Category = 'Re-Registration' THEN 1
WHEN Category = 'New' THEN 2
ELSE 3
END ASC ) rn
FROM Equipment_Registrations
) s
WHERE rn = 1
You can set the order in the CASE statement to be whatever you want - I'm afraid that without more information, that's the best solution I can offer you. If you have a known list of values that might appear in that field, it should be easy; if not, it will be a little harder to configure, but that will be based on business rules that you did not include in your original post.

How to find the next record after a specified one in SQL?

I'd like to use a single SQL query (in MySQL) to find the record which comes after one that I specify.
I.e., if the table has:
id, fruit
-- -----
1 apples
2 pears
3 oranges
I'd like to be able to do a query like:
SELECT * FROM table where previous_record has id=1 order by id;
(clearly that's not real SQL syntax, I'm just using pseudo-SQL to illustrate what I'm trying to achieve)
which would return:
2, pears
My current solution is just to fetch all the records, and look through them in PHP, but that's slower than I'd like. Is there a quicker way to do it?
I'd be happy with something that returned two rows -- i.e. the one with the specified value and the following row.
EDIT: Sorry, my question was badly worded. Unfortunately, my definition of "next" is not based on ID, but on alphabetical order of fruit name. Hence, my example above is wrong, and should return oranges, as it comes alphabetically next after apples. Is there a way to do the comparison on strings instead of ids?
After the question's edit and the simplification below, we can change it to
SELECT id FROM table WHERE fruit > 'apples' ORDER BY fruit LIMIT 1
SELECT * FROM table WHERE id > 1 ORDER BY id LIMIT 1
Even simpler
UPDATE:
SELECT * FROM table WHERE fruit > 'apples' ORDER BY fruit LIMIT 1
So simple, and no gymnastics required
Select * from Table
where id =
(Select Max(id) from Table
where id < #Id)
or, based on the string #fruitName = 'apples', or 'oranges' etc...
Select * from Table
where id =
(Select Max(id) from Table
where id < (Select id from Table
Where fruit = #fruitName))
I'm not familiar with the MySQL syntax, but with SQL Server you can do something with "top", for example:
SELECT TOP 1 * FROM table WHERE id > 1 ORDER BY id;
This assumes that the id field is unique. If it is not unique (say, a foreign key), you can do something similar and then join back against the same table.
Since I don't use MySQL, I am not sure of the syntax, but would imagine it to be similar.
Unless you specify a sort order, I don't believe the concepts of "previous" or "next" are available to you in SQL. You aren't guaranteed a particular order by the RDBMS by default. If you can sort by some column into ascending or descending order that's another matter.
This should work. The string 'apples' will need to be a parameter.
Fill in that parameter with a string, and this query will return the entire record for the first fruit after that item, in alphabetical order.
Unlike the LIMIT 1 approach, this should be platform-independent.
--STEP THREE: Get the full record w/the ID we found in step 2
select *
from
fruits fr
,(
--STEP TWO: Get the ID # of the name we found in step 1
select
min(vendor_id) min_id
from
fruits fr1
,(
--STEP ONE: Get the next name after "apples"
select min(name) next_name
from fruits frx
where frx.name > 'apples'
) minval
where fr1.name = minval.next_name
) x
where fr.vendor_id = x.min_id;
The equivalent to the LIMIT 1 approach in Oracle (just for reference) would be this:
select *
from
(
select *
from fruits frx
where frx.name > 'apples'
order by name
)
where rownum = 1
I don't know MySQL SQL but I still try
select n.id
from fruit n
, fruit p
where n.id = p.id + 1;
edit:
select n.id, n.fruitname
from fruits n
, fruits p
where n.id = p.id + 1;
edit two:
Jason Lepack has said that that doesn't work when there are gaps and that is true and I should read the question better.
I should have used analytics to sort the results on fruitname
select id
, fruitname
, lead(id) over (order by fruitname) id_next
, lead(fruitname) over (order by fruitname) fruitname_next
from fruits;
If you are using MS SQL Server 2008 (not sure if available for previous versions)...
In the event that you are trying to find the next record and you do not have a unique ID to reference in an applicable manner, try using ROW_NUMBER(). See this link
Depending on how savvy your T-SQL skill is, you can create row numbers based on your sorting order. Then you can find more than just the previous and next record. Utilize it in views or sub-queries to find another record relative to the current record's row number.
SELECT cur.id as id, nxt.id as nextId, prev.id as prevId FROM video as cur
LEFT JOIN video as nxt ON nxt.id > cur.id
LEFT JOIN video as prev ON prev.id < cur.id
WHERE cur.id = 12
ORDER BY prev.id DESC, nxt.id ASC
LIMIT 1
If you want the item with previous and next item this query lets you do just that.
This also allows You to have gaps in the data!
How about this:
Select * from table where id = 1 + 1