Get rows with a mix of specific values or null if value does not exist - sql

I have a table that looks like this.
id
value
text
type
eqPath
enabled
1
0
Unknown
NULL
NULL
True
2
1
Production
Production
NULL
True
3
2
Idle
Idle
NULL
True
4
3
Maintenance
Maintenance
NULL
True
5
4
Changeover
Changeover
NULL
True
6
5
Cleaning
Cleaning
NULL
True
7
6
Engineering
Other
NULL
True
8
7
Training
Other
NULL
True
9
8
Pause
Idle
NULL
True
10
1
Running
Production
'Seattle/Sorting/Line 1'
True
11
1
Running
Production
'Seattle/Sorting/Line 2'
True
12
5
Washing
Cleaning
'Seattle/Sorting/Line 2'
False
13
10
Locked Out
Maintenance
'Seattle/Sorting/Line 2'
False
When I use this code, I get back all of the rows with an eqPath of NULL.
SELECT *
FROM modes
WHERE eqPath IS NULL
id
value
text
type
eqPath
enabled
1
0
Unknown
NULL
NULL
True
2
1
Production
Production
NULL
True
3
2
Idle
Idle
NULL
True
4
3
Maintenance
Maintenance
NULL
True
5
4
Changeover
Changeover
NULL
True
6
5
Cleaning
Cleaning
NULL
True
7
6
Engineering
Other
NULL
True
8
7
Training
Other
NULL
True
9
8
Pause
Idle
NULL
True
Now I need one that returns the same table, but if the user requests a specific eqPath, then it would also show up in the list, BUT the value column has to be unique with the row containing the eqPath to replace the row with the NULL
eqPath.
id
value
text
type
eqPath
enabled
1
0
Unknown
NULL
NULL
True
11
1
Running
Production
'Seattle/Sorting/Line 2'
True
3
2
Idle
Idle
NULL
True
4
3
Maintenance
Maintenance
NULL
True
5
4
Changeover
Changeover
NULL
True
12
5
Washing
Cleaning
'Seattle/Sorting/Line 2'
False
7
6
Engineering
Other
NULL
True
8
7
Training
Other
NULL
True
9
8
Pause
Idle
NULL
True
13
10
Locked Out
Maintenance
'Seattle/Sorting/Line 2'
False
This is the code I am trying, but I realize it is wrong.
SELECT DISTINCT *
FROM modes
WHERE eqPath = ?
OR eqPath IS NULL
GROUP BY value

You can use ROW_NUMBER to mark the rows and use it in filter to get the expected result.
A sql query will be something like -
select id, value, text, type, eqPath, enabled
from
(select * ,
row_number() over( partition by value order by eqPath desc) rn
from <your-table>
where (eqPath is null or eqPath = ?) ) tbl
where rn = 1
order by value
the row_number in the query will put a row number for each rows and resets when the value changes, so finally those rows with row number matching 1 will the ones we need to fetch.
here is a fiddle

I think I came up with a solution:
SELECT *
FROM modes
WHERE eqPath IS NULL
AND value NOT IN (
SELECT value
FROM modes
WHERE eqPath = ?
)
UNION
SELECT *
FROM modes
WHERE eqPath = ?
ORDER BY value

Related

Count of total value and count of individual value

I have a table like:
Id
type
status
1
coach
1.0
2
coach
True
3
client
NULL
4
coach
False
5
client
NULL
6
coach
False
7
client
NULL
8
coach
True
9
coach
1.0
10
client
NULL
I want to:
create a column where coach status is active when value is 1.0 and True else status should be inactive
add count of active and inactive values in another column and and total coach count as another column
Here's the expected output:
Id
type
Status
totalcount
status count
1
coach
Active
6
4
2
coach
Active
6
4
4
coach
Inactive
6
2
6
coach
Inactive
6
2
8
coach
Active
6
4
9
coach
Active
6
4
I tried this code
Select id,
(case when status in (1.0,True)
then 'Active'
else 'Inactive'
end) as Status
from table
Where type ='Coach'
But unable to add count of active and inactive and total coach.
Try the following combination of case expressions coupled with a windowed count:
select id, type,
case when status in ('1.0','True') then 'Active' else 'Inactive' end as Status,
Count(*) over() TotalCount,
Count(*) over(partition by case when status in ('1.0','True') then 1 end) StatusCount
from t
where type='coach'
order by Id;

Add flag on SQL Server table, based on pair of features [duplicate]

This question already has answers here:
Get top 1 row of each group
(19 answers)
Closed 8 months ago.
I have a table in SQL Server with Id, Code and Prod. I want to add a flag and end up like:
Id Code Prod Flag
0 101 A 0
1 101 B 0
2 101 A 1
3 101 A 1
4 101 B 1
5 160 B 0
6 160 A 0
7 160 B 1
8 190 A 0
9 190 B 0
For each pair Code-Prod (eg. 101-A, which has 3 cases), the flag should assume 0 for the first Id, 1 otherwise.
How do I do that?
This is ideally solved with row_number() window function, combined with an updatable CTE:
with upd as (
select *, Row_Number() over(partition by Concat(code,prod) order by id) rn
from t
)
update upd
set flag = case when rn = 1 then 0 else 1 end;

BigQuery. CASE WHEN

I am working on BigQuery.
I need to created a query that counts if the version is a fix or not. The first version is not a fix and the ones that follow are a fix. Unless the first version has been created by system, in that case, the first and second versions are not a fix.
Now my query count only the first version as a non-fix, regardless of who created it.
My query is:
Select
CASE WHEN ROW_NUMBER()
OVER (PARTITION BY id_site ORDER BY timestamp ASC) = 1 THEN false ELSE true END is_fix,
FROM table1
Table1
ID ID_site Timestamp Version version_created_by
1 1 1/1/2022 4624653 system
2 1 1/2/2022 4624651 1234
3 1 1/3/2022 4624655 4567
4 2 5/2/2022 4567830 1234
5 2 5/3/2022 4567835 5678
6 3 5/4/2022 7567836 8907
7 3 5/5/2022 7890000 9807
Expected result:
ID ID_site Timestamp Version version_created_by is_fix
1 1 1/1/2022 4624653 system FALSE
2 1 1/2/2022 4624651 1234 FALSE
3 1 1/3/2022 4624655 4567 TRUE
4 2 5/2/2022 4567830 1234 FALSE
5 2 5/3/2022 4567835 5678 TRUE
6 3 5/4/2022 7567836 8907 FALSE
7 3 5/5/2022 7890000 9807 TRUE
Try below approach
SELECT
*,
CASE WHEN ROW_NUMBER() OVER (
PARTITION BY id_site
ORDER BY timestamp DESC
) <= t.cnt
THEN true ELSE false
END is_fix,
FROM (
Select
*,
CASE WHEN version_created_by = 'system' THEN 2 ELSE 1 END cnt
FROM table1
) as t
ORDER BY id
my test data & result are ...
id id_site timestamp version version_created_by
1 1 2022-01-01T00:00:00Z 4624653 system
2 1 2022-01-02T00:00:00Z 4624651 1234
3 1 2022-01-03T00:00:00Z 4624655 4567
4 2 2022-05-02T00:00:00Z 4567830 1234
5 2 2022-05-03T00:00:00Z 4567835 5678
6 3 2022-05-04T00:00:00Z 7567836 8907
7 3 2022-05-05T00:00:00Z 7890000 9807
id id_site timestamp version version_created_by cnt is_fix
1 1 2022-01-01T00:00:00Z 4624653 system 2 false
2 1 2022-01-02T00:00:00Z 4624651 1234 1 false
3 1 2022-01-03T00:00:00Z 4624655 4567 1 true
4 2 2022-05-02T00:00:00Z 4567830 1234 1 false
5 2 2022-05-03T00:00:00Z 4567835 5678 1 true
6 3 2022-05-04T00:00:00Z 7567836 8907 1 false
7 3 2022-05-05T00:00:00Z 7890000 9807 1 true
To match the format with the expected result,
SELECT * EXCEPT (cnt)
FROM (
SELECT
*,
CASE WHEN ROW_NUMBER() OVER (
PARTITION BY id_site
ORDER BY timestamp DESC
) <= t.cnt
THEN true ELSE false
END is_fix,
FROM (
Select
*,
CASE WHEN version_created_by = 'system' THEN 2 ELSE 1 END cnt
FROM table1
) as t
)
ORDER BY id
You can check if the 1st version was created by 'system' with FIRST_VALUE() window function:
SELECT *,
CASE ROW_NUMBER() OVER (PARTITION BY id_site ORDER BY timestamp)
WHEN 1 THEN false
WHEN 2 THEN FIRST_VALUE(version_created_by) OVER (PARTITION BY id_site ORDER BY timestamp) <> 'system'
ELSE true
END is_fix
FROM table1;
See the demo (for MySql).

Select first value then fill with null for unique id

I'm using a Postgres database.
I've been trying to resolve this for hours and read dozens of topics with no result yet
Since I don't know how to explain my issue with words, here is what I need by example :
My query is
select distinct chiffre_affaires.contrat_pentete_id,
chiffre_affaires.chiffre_affaires_id,
chiffre_affaires.chiffre_affaires_montant_total
from chiffre_affaires;
Current output :
contrat_pentete_id
chiffre_affaires_id
chiffre_affaires_montant_total
1
1
111.7848
1
2
111.7848
1
3
111.7848
1
4
111.7848
1
5
111.7848
1
6
111.7848
2
7
90
2
8
90
2
9
90
2
10
90
Expected output :
null values can be replaced by 0, both null or 0 would work
contrat_pentete_id
chiffre_affaires_id
chiffre_affaires_montant_total
1
1
111.7848
1
2
null
1
3
null
1
4
null
1
5
null
1
6
null
2
7
90
2
8
null
2
9
null
2
10
null
Thank you in advance for any help !
Trying to understand what you want to achieve : for a group of rows with same contrat_pentete_id, ordered by chiffre_affaires_id ASC, you want to display the
chiffre_affaires_montant_total value for the first row, and NULL for the next rows. If so, you can try this :
SELECT DISTINCT
ca.contrat_pentete_id,
ca.chiffre_affaires_id,
CASE
WHEN ca.chiffre_affaires_id = first_value (ca.chiffre_affaires_id) OVER (ORDER BY ca.chiffre_affaires_id)
THEN ca.chiffre_affaires_montant_total
ELSE NULL
END AS ca.chiffre_affaires_montant_total
FROM chiffre_affaires AS ca
ORDER BY ca.contrat_pentete_id, ca.chiffre_affaires_id
Thanks to Edouard H. I finally wrote a script that did the job.
Here is the solution :
SELECT DISTINCT ca.contrat_pentete_id,
ca.chiffre_affaires_id,
ca.chiffre_affaires_annee_mois,
CASE
WHEN ca.chiffre_affaires_id =
first_value(ca.chiffre_affaires_id) OVER (PARTITION BY ca.contrat_pentete_id ORDER BY ca.chiffre_affaires_annee_mois)
THEN ca.chiffre_affaires_montant_total
END AS montant_facture
FROM chiffre_affaires AS ca
ORDER BY ca.contrat_pentete_id;

Value carry forword

I have below SQL Query..
SELECT dbo.O3.[s.no] AS [O3_Sn.NO], dbo.O5.[s.no] AS [O5_Sn.NO], dbo.O3.O3, dbo.O5.O5,
case when dbo.O3.[s.no] > dbo.O5.[s.no] then 'true' else 'false' end as ComparisonColumn
FROM dbo.O3 INNER JOIN
dbo.O5 ON dbo.O3.[s.no] = dbo.O5.[s.no]
When I run I am getting below output..
O3_Sn.NO O5_Sn.NO O3 O5 ComparisonColumn
1 1 10 11 TRUE
2 2 12 13 TRUE
3 3 11 10 FALSE
4 4 13 11 FALSE
5 5 15 16 TRUE
6 6 10 11 TRUE
7 7 12 13 TRUE
I want to remember the value of TRUE / False and should ignore if it is repeated untill i get a reverse case i.e., for TRUE , False.. and FOR False .. TRUE
Below is the out i should get it..
O3_Sn.NO O5_Sn.NO O3 O5 ComparisonColumn New_Case_Carry_value
1 1 10 11 TRUE TRUE
2 2 12 13 TRUE NULL
3 3 11 10 FALSE FALSE
4 4 13 11 FALSE NULL
5 5 15 16 TRUE TRUE
6 6 10 11 TRUE NULL
7 7 12 13 TRUE NULL
You can order your output using row_number() to compare a value with a value of the previous record:
with cIntermediate as (
SELECT dbo.O3.[s.no] AS [O3_Sn.NO], dbo.O5.[s.no] AS [O5_Sn.NO], dbo.O3.O3, dbo.O5.O5,
case when dbo.O3.[s.no] > dbo.O5.[s.no] then 'true' else 'false' end
as ComparisonColumn,
rowno = row_number() over
(order by dbo.O3.[s.no], dbo.O5.[s.no], dbo.O3.O3, dbo.O5.O5)
FROM dbo.O3 INNER JOIN dbo.O5 ON dbo.O3.[s.no] = dbo.O5.[s.no]
)
select i1.*,
case when i1.ComparisonColumn = i2.ComparisonColumn then null
else i1.ComparisonColumn end as NewCaseCarryValue
from cIntermediate i1
left join cIntermediate i2 on i2.rowno=i1.rowno-1
Ok, I will explain the concept to you, and I am sure you will be able to figure it out for yourself.
Your final result you published with all the true and false columns, that needs to become a temporary table, like this, but with some kind of identity column:
SELECT dbo.o3.[s.no] AS [O3_Sn.NO]
,dbo.o5.[s.no] AS [O5_Sn.NO]
,dbo.o3.o3
,dbo.o5.o5
,CASE
WHEN dbo.o3.[s.no] > dbo.o5.[s.no] THEN 'true'
ELSE 'false'
END AS comparisoncolumn
, ROW_NUMBER() OVER(ORDER BY dbo.o3.[s.no]) AS ident_col
INTO #temp
FROM dbo.o3
INNER JOIN dbo.o5
ON dbo.o3.[s.no] = dbo.o5.[s.no]
Then what you need to do is to select from #temp, and self join to #temp in a similar manner as here:
SELECT a.*
, CASE WHEN a.comparisoncolumn = b.comparisoncolumn THEN NULL ELSE a.comparisoncolumn END AS final_comparisoncolumn
FROM #temp a
LEFT JOIN #temp b ON a.ident_col = b.ident_col - 1
Then do a case statement to figure out if you need to print null, or true or false.
Play around with this concept, I am sure you will be able to work it out from here.
You can do an left join on the table itself (SN = SN-1) and compare the ComparisonColumn