Trying to understand simple SQL query with case statement - sql

I am trying to understand this query:
SELECT *
FROM servers
ORDER BY
CASE
WHEN status = "ACTIVE" THEN 1
WHEN status = "INACTIVE" THEN 2
ELSE 3
END
I know this is selecting all rows from the server table and ordering them first with where column status = "ACTIVE" and then where status = "INACTIVE."
What is the syntax THEN 1...THEN 2 ELSE 3 END mean? I know END is to close the case statement, but what are 1, 2, and 3?

Your CASE clause is in the ORDER BY section - it doesn't become part of the output, it's just used by the SQL engine for sorting.
The 1,2,3 are sortable values.
Basically it' saying to put the ACTIVE rows first (1), then the INACTIVE rows (2), then any rows that are neither (3) at the end.
Given that ACTIVE and INACTIVE sort the same way, I guess there are other values in the table that don't sort in that order (maybe CLOSED or DORMANT which would come before INACTIVE

Related

SQL - How to keep the last row if it meets a condition, but remove other rows beforehand which meet the same condition

I'm coming across an SQL issue which I could do with some advice on.
I have an example below showing actions taken between different energy suppliers for dispute cases. The action_time_start is when supplier 1 sends an action, and action_time_end is when supplier 2 sends a response.
The row number is not included in the main table but I have added it in here for visibility.
dispute_id
supplier_1_action_sent
supplier_2_action_response
action_time_start
action_time_end
row_num
847294
Proposal received (P)
Accept Proposal
2023-01-23
2023-01-23
4
847294
Agreement made (Y)
NULL
2023-01-24
NULL
3
847294
Agreement made (Y)
Close Dispute
2023-01-25
2023-02-03
1
847294
Proposal received (P)
NULL
2023-02-3
NULL
1
I need to:
Include columns 2 and 4 in the results.
Include column 1 in the results (the last row), where the result for action_time_end is null.
Remove column 3 from results, where action_time_end is null.
For the table overall, I need to remove any columns where action_time_end is null except for when it is the last row, for each dispute_id. I also need to keep all columns in the results where action_time_end is not null.
If the last row has a value in action_time_end which is not null then this needs to be kept in, and all rows before where it's null removed.
Any suggestions here?
I have tried a number of different solutions, including:
Using MAX(COALESCE(TO_DATE(action_time_end), DATE '9999-01-01')) and filtered out instances where the action_time_start < action_time_end and action_time_end != '9999-01-01'.
Including row_num and filtering where row_num = 1 and action_time_end is not null
Doing a complex CASE WHEN in the last where clause of the query
The issue is that I'm not sure how to keep in the last row but remove all the others when a certain condition is met.
We can use CASE expressions here:
SELECT
CASE WHEN action_time_end IS NULL THEN dispute_id END AS dispute_id,
supplier_1_action_sent,
CASE WHEN action_time_end IS NOT NULL THEN supplier_2_action_response END AS supplier_2_action_response,
action_time_start
FROM yourTable;

Counting how many times one specific value changed to another specific value in order of date range and grouped by ID

I have a table like below where I need to query a count of how many times each ID went from specifically 'Waste Sale' in one value to 'On Stop' in the very next value based on ascending date and if there are no instances of this, the count will be 0
ID
Stage name
Stage Changed Date
1
Waste Sale
06-05-2022
1
On Stop
08-06-2022
1
Cancelled
09-02-2022
2
Waste Sale
06-05-2022
2
On Stop
07-05-2022
2
Waste Sale
08-06-2022
2
On Stop
10-07-2022
3
Cancelled
10-07-2022
3
On Stop
11-07-2022
The result I would be looking for based on the above table would be something like this:
ID
Count of 'Waste Sales to On Stops'
1
1
2
2
3
0
ID 1 having a count of 1 because there was one instance of 'Waste Sale' changing to 'On Stop' in the very next value based on date range
ID 3 having a count of 0 because even though the stage name changed to 'On Stop' the previous value based on date range wasn't 'Waste Sale'.
I have a hunch I would have to use something like LEAD() and GROUP BY/ ORDER BY but since I'm so new to SQL would really appreciate some help on the specific syntax and coding. Any version of SQL is okay.
We can use window function lead to take a peek at the next value of the query result.
select distinct id,
(
select count(*)
from
(
select *,
lead(stage_name)
over(
partition by id
order by stage_changed_date)
as stage_next
from sales s2
) s3
where s3.id = s1.id
and s3.stage_name = 'waste sale'
and s3.stage_next = 'on stop'
) as count_of_waste_sales_to_on_stop
from sales s1
order by id;
Query above uses lead(stage_name) over(partition by id order by stage_changed_date) to get the next stage_name in the query result while segregating it by id and order it based on stage_changed_date. Check the query on DB Fiddle.
Note:
I have no experience in zoho, so i'm unsure if the query will 100% works or not. They said it supported ansi-sql, however there might some differences with MySQL due to reasons.
The column names are not the exact same with op question due to testing only done using DB Fiddle.
There might better query out there waiting to be written.

Max match same numbers from each row

To generate 1mln rows of report with the below mentioned script is taking almost 2 days so, really appreciate if somebody could help me with different script which the report can be generated within 10-15mins please.
The requirement of the report is as following;
Table “cover” contains 5mln rows & 6 columns of data and likewise table “data” contains 500,000 rows and 6 columns.
So, each numbers of the rows in table cover has to go through table date and provide the maximum matches.
For instance, as mentioned on the below tables, there could be 3 matches in row #1, 2 matches in row #2 and 5 matches in row #3 so the script has to select the max selection which is 5 in row #3.
Sample table
UPDATE public.cover_sheet AS fc
SET maxmatch = (SELECT MAX(tmp.mtch)
FROM (
SELECT (SELECT CASE WHEN fc.a=drwo.a THEN 1 ELSE 0 END) +
(SELECT CASE WHEN fc.b=drwo.b THEN 1 ELSE 0 END) +
(SELECT CASE WHEN fc.c=drwo.c THEN 1 ELSE 0 END) +
(SELECT CASE WHEN fc.d=drwo.d THEN 1 ELSE 0 END) +
(SELECT CASE WHEN fc.e=drwo.e THEN 1 ELSE 0 END) +
(SELECT CASE WHEN fc.f=drwo.f THEN 1 ELSE 0 END) AS mtch
FROM public.data AS drwo
) AS tmp)
WHERE fc.code>0;
SELECT *
FROM public.cover_sheet AS fc
WHERE fc.maxmatch>0;
As #a_horse_with_no_name mentioned in the comment to the question, your question is not clear...
Seems, you want to get the number of records which 6 fields from both tables are equal.
I'd suggest to:
reduce the number of select statements, then the speed of query execution will increase,
split your query into few smaller ones (good practice), to check your logic,
use join to get equal data, see: Visual Representation of SQL Joins
use subquery or cte to get result on which you'll be able to update table.
I think you want to get result as follow:
SELECT COUNT(*) mtch
FROM public.cover_sheet AS fc INNER JOIN public.data AS drwo ON
fc.a=drwo.a AND fc.b=drwo.b AND fc.c=drwo.c AND fc.d=drwo.d AND fc.e=drwo.e AND fc.f=drwo.f
If i'm not wrong and above query is correct, the time of execution of above query will reduce to about 1-2 minutes.
Finally, update query may look like:
WITH qry AS
(
-- proper select statement here
)
UPDATE public.cover_sheet AS fc
SET maxmatch = qry.<fieldname>
FROM qry
WHERE fc.code>0 AND fc.<key> = qry.<key>;
Note:
I do not see your data and i know nothing about its structure, relationships, etc. So, you have to change above query to your needs.

Updating columns based on a combine rows value on the same table

Please assist if possible, I have used Stuff to combine rows into a single row based on other columns. However I want to turn each of the unique items into it's own column with a number showing if it exists, e.g. 1 or 0 and then doing the same for all subsequent rows?
I have been able to create the columns but I can't get them to update per whats in the one column.
But I want it to be dynamic so matter how many different names appear in categories it creates a new column and adds 1 or 0 if it appears or not
How about something like this for SQL Server?
strSQL = "SELECT Category, CASE WHEN Category IS NOT NULL THEN 1 ELSE 0 END AS IsCategoryExist FROM MyTable"
Sample data (the 2nd column shows as 1 if the first column is non-blank):
Cars, 1
[Blank], 0
Airplanes, 1
Radios, 1

Get specific "version" of a column

I have an app that uses SQLite to store data locally. There may be more than one file storing the data. All the files contain a list of items, but only one of them has the "correct" status for the current user (basically, there is a "user" db in $HOME and a "system-wide" one in /etc).
Usually, both files will contain the same list of items, and only the status column will differ. If, however, either contains items not in both, I want that data as well.
SQLite does not have FULL OUTER JOIN.
A solution I have come up with is this:
SELECT item, group_concat(status) AS status FROM (SELECT item,status FROM items UNION SELECT item,status FROM otherdb.items) GROUP BY item;
And then parsing the comma-separated "status" output to get the "right" status. I would like a pure SQL solution, however.
The values I want for status are:
If any = 1, status = 1
elif any = -1, status = -1
elif any = 2, status = 2
elif any = -2, status = -2
else status = 0 or NULL
status may only (in the db) be -2,-1,0,NULL,1,2 so this covers all data.
If there is a solution that only gives whichever one is non-zero and non-null, that could work too, although I would prefer the above.
I would sugest you one approach:
1. create a temp table, one adittional column for a flag "otherbd";
2. throw everything from the 2 tables in there;
3. delete the lines you don't want;
Create a status priority table with the following values
status priority
1 5
-1 4
2 3
-2 2
0 1
NULL 0
The concept is to join your two tables against this StatusPriorty table, Group the records and use MAX(Priority) to get your results