How to combine records of same data? - sql

I have to select students from database on the bases of their status,
status could be active or Inactive, there could be some students with the status active and some with status Inactive in db.
I have to select students with same status at a time.
can be done with a very simple query but problem is this query is generated automatically on run time and I can't give hard-coded status.
How to retrieve records of same status at a time?
EDIT: For Instance there is these records in db
Student A: Status Inactive
Student B: Status Inactive
Student C: Status Active
Student D: Status Inactive
Now I need to retrieve Students A,B and D in a single result set cause they have same status i-e "Inactive" while need to retrieve Student D in a seperate result set cause it has different status i-e "Active".
Hope now the scenario is clear.

If your "system" automatically alters the query, then you are out of luck entirely. There is nothing you can do other than change the system to allow you to alter the query.
But if you can, simply use an OR statement
ie.
select studentid, studentname, status
where status = 'value1' OR status = 'value2'
or more simply ...
select studentid, studentname, status
where status in ('value1','value2')
Simple.

If you need two recordset, use two query, otherwise simpy use the sorting:
ORDER BY status, name

then try this ...
select studentid, studentname, status where (status = 'value1' AND status <> 'value2') OR
(status <> 'value1' AND status = 'value2')

Related

In SQL, is there something like COALESCE() to qualify Column values which are NOT NULL?

I have an "Order"Table which houses "Status"Column. Values under Status = ('Completed','Sold','In-Process','Released','NotStarted').
Even though there is no sequence or hierarchy for that in the table, we can perceive the sequence as below.
1 NotStarted
2 Released
3 In-Process
4 Sold
5 Completed
So 'Completed' is the highest status and each order goes through these Statuses until they are Completed. if they are not completed yet, they should be in one of the other status.
When I filter on Completed, I miss out on the other records. When I include all Status, I get multiple records of same order such as 1 record for Released, 1 record for InProcess, etc (i.e, the various stages of the order)
select * from OrderTable
where Status = 'Completed'
I want to have the ability to do something like this --
COALESCE(Completed,Sold,In-Process,Released,NotStarted, NULL)
In other words, I want to get the highest record for that status and only 1 record for each order.
Is this possible in Sql?
One option is to use ROW_NUMBER() with a Case expression to establish your ordering.
SELECT *
FROM
(
SELECT OrderNumber,
Status,
ROW_NUMBER() OVER (PARTITION BY OrderNumber ORDER BY
CASE Status
WHEN 'NotStarted' THEN 1
WHEN 'Released' THEN 2
WHEN 'In-Process' THEN 3
WHEN 'Sold' THEN 4
WHEN 'Completed' THEN 5
END DESC) as Order_Status_Rank
FROM OrderTable
) dt
WHERE Order_Status_Rank = 1;
See it in action here
If you used the numbers shown in your list instead of the text, all you would have to do is select Top 1 and sort on the number. You can use another table to store the number/entry data. By the way, this would also prevent erroneous data entry.

if-then-else construction in complex stored procedure

I am relatively new to sql queries and I was wondering how to create a complex stored procedure. My database runs on SQL server.
I have a table customer (id, name) and a table customer_events (id, customer_id, timestamp, action_type). I want add a calculated field customer_status to table customer which is
0: (if there is no event for this customer in customer_events) or (the most recent event is > 5 minutes ago)
1: if the most recent event is < 5 minutes ago and action_type=0
2: if the most recent event is < 5 minutes ago and action_type=1
Can I use if-then-else constructions or should I solve this challenge differently?
As you mentioned in comments, you actually want to add a field to a select query, and in a general sense what you want is a CASE statement. They work like this:
SELECT field1,
field2,
CASE
WHEN some_condition THEN some_result
WHEN another_condition THEN another_result
END AS field_alias
FROM table
Applied to your specific scenario, well it's not totally straightforward. You're certainly going to need to left join your status table, you also want to aggregate to find the most recent event, along with that event's action type. Once you have that information, the case statement is straightforward.
Always hard to write sql without access to your data, but something like:
SELECT c.id,
c.name,
CASE
WHEN e.id IS NULL OR DATEDIFF(minute,e.timestamp,getDate())>=5 THEN 0
WHEN DATEDIFF(minute,e.timestamp,getDate())<5 AND s.action_type=1 THEN 1
WHEN DATEDIFF(minute,e.timestamp,getDate())<5 AND s.action_type=0 THEN 2
END as customer_status
FROM clients c
LEFT JOIN (
SELECT id, client_id, action_type,
rank() OVER(partition by client_id order by timestamp desc) AS r
FROM customer_events
) e
ON c.id=e.client_id AND e.r=1
The core of this is the subquery in the middle, it's using a rank funtion to give a number to each status by client_id ordered by the timestamp descending. Therefore every record with a rank of 1 will be the most recent (for that client). Thereafter, you simply join it on to the client table, and use it to determine the right value for customer_status
Presuming you get the event info into "Most_Recent_Event_Mins_Ago". If none it will be NULL.
SELECT Id, Name,
CASE
WHEN Most_Recent_Event_Mins_Ago IS NULL THEN 0
WHEN Most_Recent_Event_Mins_Ago <5 AND Action_type = 0 THEN 1
WHEN Most_Recent_Event_Mins_Ago <5 AND Action_type = 1 THEN 0
..other scenarions
ELSE yourDefaultValueForStatus
END as Status
FROM customer
WHERE
...
...

SQL count, use only last record

can someone help me about counting rows in sql. I have a table, archive, in which I have bank account and status of that account. One account can have and usually have more records, in my count I have to use last record, not records before. Example:
account status
5552222 A
5552222 B
5552222 A
**5552222 B**
4445896 A
4445896 B
**4445896 A**
I have to use this who are bold. Based on this there is one B(blocked) and one A(active) account. I have column datetime, which can tell me what is last record. I just need query to count that
Assuming you want to count based on the most current row for an account:
SELECT tab.status,
COUNT(*)
FROM tab JOIN
(
SELECT account, MAX(datetime) AS maxdate
FROM tab
GROUP BY account
) AS dt
ON tab.account = dt.account
AND tab.datetime = dt.maxtime
GROUP BY tab.Status
SELECT COUNT(*)
FROM yourTable
WHERE Status='B'
or
WHERE AccountName LIKE '%B'
Edit: After OP modified the question to include the table data.
So, the problem is that the same account number can occur multiple times, and you want to count on the basis of last status of the account.
If the account is currently blocked, you would like to count it, irrespective of the number of times it gets blocked earlier.
Assumption: You have a date type column in your table which shows the date when the record's (with new status value) was inserted (or it may be an identity field which keeps track of the order of records created in the table)
The query will be:
SELECT COUNT (*)
FROM
(
SELECT DISTINCT
acNumber,
( SELECT Max(identityField_or_dateField)
FROM tableName t
WHERE t.acNumber = t2.acNumber AND Status='B')
FROM tableName t2
WHERE
( SELECT Max(identityField_or_dateField)
FROM tableName t
WHERE t.acNumber = t2.acNumber AND Status='B') IS NOT NULL
) tblAlias
Glad to help! Please remember to accept the answer if you found it helpful.

dynamic where condition in SQL from a configurable table

CONDITION TABLE (T_CONDITION_TABLE)
COLUMN_NAME COLUMN_VALUE
USER COUNT 0
USER COUNT 1
STATUS ACTIVE
STATUS APPROVED
Suggest a query:
SELECT * FROM T_MASTER_TABLE WHERE ---- IN (SELECT * FROM T_CONDITION_TABLE)
The records in T_CONDITION_TABLE is dynamic and can include new values frequently.
If what you want as output is all the records in the T_MASTER_TABLE where your records satisfy the Status in T_CONDITION_TABLE, then u can use the WHERE Condition as
WHERE STATUS IN(Select DISTINCT STATUS FROM T_CONDITION_TABLE)
If you want to limit it with the user count use this.
WHERE COUNT(USER) IN(SELECT DISTINCT USERCOUNT FROM T_CONDITION TABLE)
If you want still more clearer answers, phrase your question properly.

SQL Precedence Query

I have a logging table which has three columns. One column is a unique identifier, One Column is called "Name" and the other is "Status".
Values in the Name column can repeat so that you might see Name "Joe" in multiple rows. Name "Joe" might have a row with a status "open", another row with a status "closed", another with "waiting" and maybe one for "hold". I would like to, using a defined precedence in this highest to lowest order:("Closed","Hold","Waiting" and "Open") pull the highest ranking row for each Name and ignore the others. Anyone know a simple way to do this?
BTW, not every Name will have all status representations, so "Joe" might only have a row for "waiting" and "hold", or maybe just "waiting".
I would create a second table named something like "Status_Precedence", with rows like:
Status | Order
---------------
Closed | 1
Hold | 2
Waiting | 3
Open | 4
In your query of the other table, do a join to this table (on Status_Precedence.Status) and then you can ORDER BY Status_Precedence.Order.
If you don't want to create another table, you can assign numeric precedence using a SELECT CASE
Select Name, Status, Case Status
When 'Closed' then 1
When 'Hold' then 2
When 'Waiting' then 3
When 'Open' Then 4
END
as StatusID
From Logging
Order By StatusId -- Order based on Case
A lookup table is also a good solution though.
I ended up using matt b's solution and using this final query to filter out the lower ranked (lower bing higher numbered).
SELECT * from [TABLE] tb
LEFT JOIN Status_Precedence sp ON tb.Status = sp.Status
WHERE sp.Rank = (SELECT MIN(sp2.rank)
FROM[Table] tb2
LEFT JOIN Status_Precedence sp2 ON tb2.Status = sp2.Status
WHERE tb.Status = tb2.Status)
order by tb.[name]