I have following table in my SQL Server database:
| ID | Class | CId | PId
| 7865 | Add Class for Prop | 1043 | 1
| 82 | Advanced Carpet Spotting Advanced Carpet Spotting | 1043 | 1
| 82 | Advanced Carpet Spotting Advanced Carpet Spotting | 1042 | 1
| 7863 | aTesting | 1042 | 0
| 7218 | aUnique | 1042 | 0
| 85 | Body Mechanics | 1042 | 1
| 88 | Carpet Bonnet Cleaning | 1044 | 0
| 89 | Carpet Shampooing/Extraction | 1044 | 1
| 7829 | Class 10 | 1044 | 0
I have multiple CId and PId
If distinct CId have their corresponding PId = 1 Then,
Set CId = 1 Otherwise 0
I want output like this
| CId | Status | Count
| 1042 | 0 | 4
| 1043 | 1 | 2
| 1044 | 0 | 3
I can get required output by using multiple queries but I want more optimized one .
Please suggest a solution. Thank you.
select cid,
case when count(case when pid = 1 then 1 end) > 0
then 1
else 0
end as status,
count(*) as count
from your_table
group by cid
If PId is always 1 and 0, you can do the following.
SELECT
CID,
AVG([Status] * 1) AS [Status],
COUNT(*) AS [Count]
FROM
YourTable
GROUP BY
CID
Use a CASE expression to check whether the sum of PId is equal to count of PId.
Query
select [CId],
case when sum([Cid]) = count([CId]) then 1
else 0 end as [Status],
count([CId]) as [Count]
from [your_table_name]
group by [CId];
Also PId should have only 1 and 0 values.
Related
I want to flag only the first duplicate ID-VL combination in the dataset shown below. Column FirstOccurence is what I want the end result to be.
ID VL FirstOccurence
1 a 1
1 b 1
2 a 1
2 a 0
3 a 1
3 a 0
4 a 1
4 a 0
5 a 1
5 b 1
5 a 0
There is currently not a unique index available in the original table.
Is there any way to do this with for instance the LAG-functionality? I cannot find any examples online that result in the flagging of duplicates. Any suggestions are much appreciated!
Kind regards,
Igor
One method is with ROW_NUMBER() along with a CASE expression:
SELECT
ID
,VL
,CASE ROW_NUMBER() OVER(PARTITION BY ID, VL ORDER BY ID, VL) WHEN 1 THEN 1 ELSE 0 END AS FirstOccurance
FROM dbo.example
ORDER BY
ID
,VL
,FirstOccurance;
Results:
+----+----+----------------+
| ID | VL | FirstOccurance |
+----+----+----------------+
| 1 | a | 1 |
| 1 | b | 1 |
| 2 | a | 0 |
| 2 | a | 1 |
| 3 | a | 0 |
| 3 | a | 1 |
| 4 | a | 0 |
| 4 | a | 1 |
| 5 | a | 0 |
| 5 | a | 1 |
| 5 | b | 1 |
+----+----+----------------+
Note that this result order differs from your end result. If there are one or more columns present in the table that provide the same ordering as the results in you question, specify that in the ORDER BY clause instead.
I have a parent and child table like the following:
Parent Table
CourseId | CourseName
1 | MVC training
and the
Child Table
Id | StudentId | CourseId | AttnDate
1 | 33 | 1 | 6/1/2019
2 | 33 | 1 | 6/2/2019
3 | 33 | 1 | 6/3/2019
4 | 34 | 1 | 6/1/2019
5 | 34 | 1 | 6/2/2019
6 | 34 | 1 | 6/3/2019
I searched over google to use rownumber to make this but could not make it.
No idea
I want the final result like the following table. What I need is to change the 33 to 1 and 34 to 2:
Id | StudentId | CourseId | AttnDate
1 | 1 | 1 | 6/1/2019
2 | 1 | 1 | 6/2/2019
3 | 1 | 1 | 6/3/2019
4 | 2 | 1 | 6/1/2019
5 | 2 | 1 | 6/2/2019
6 | 2 | 1 | 6/3/2019
Try this using DENSE_RANK()
SELECT Id,
DENSE_RANK()OVER( ORDER BY StudentId) AS StudentId,
CourseId,
AttnDate
FROM Parent p
INNER JOIN Child c ON c.CourseId = p.CourseId
ORDER bY p.ID
Why do you need to "change the 33 to 1 and 34 to 2"? Is it for the purpose of assigning unique rank number for each distinct row within the partition (data grouped by StudentId)?
If it's true, then SQL Server DENSE_RANK ranking function is what you need
SELECT *,
DENSE_RANK() OVER(ORDER BY c.StudentId) AS RowNumberRank -- here is your rank number (StudentId in your final result)
FROM Child c
Hard to phrase the title for this one.
I have a table of data which contains a row per invoice. For example:
| Invoice ID | Customer Key | Date | Value | Something |
| ---------- | ------------ | ---------- | ------| --------- |
| 1 | A | 08/02/2019 | 100 | 1 |
| 2 | B | 07/02/2019 | 14 | 0 |
| 3 | A | 06/02/2019 | 234 | 1 |
| 4 | A | 05/02/2019 | 74 | 1 |
| 5 | B | 04/02/2019 | 11 | 1 |
| 6 | A | 03/02/2019 | 12 | 0 |
I need to add another column that counts the number of previous rows per CustomerKey, but only if "Something" is equal to 1, so that it returns this:
| Invoice ID | Customer Key | Date | Value | Something | Count |
| ---------- | ------------ | ---------- | ------| --------- | ----- |
| 1 | A | 08/02/2019 | 100 | 1 | 2 |
| 2 | B | 07/02/2019 | 14 | 0 | 1 |
| 3 | A | 06/02/2019 | 234 | 1 | 1 |
| 4 | A | 05/02/2019 | 74 | 1 | 0 |
| 5 | B | 04/02/2019 | 11 | 1 | 0 |
| 6 | A | 03/02/2019 | 12 | 0 | 0 |
I know I can do this using either a CTE like this...
(
select
count(*)
from table
where
[Customer Key] = t.[Customer Key]
and [Date] < t.[Date]
and Something = 1
)
But I have a lot of data and that's pretty slow. I know I can also use cross apply to achieve the same thing, but as far as I can tell that's not any better performing than just using a CTE.
So; is there a more efficient means of achieving this, or do I just suck it up?
EDIT: I originally posted this without the requirement that only rows where Something = 1 are counted. Mea culpa - I asked it in a hurry. Unfortunately I think that this means I can't use row_number() over (partition by [Customer Key])
Assuming you're using SQL Server 2012+ you can use Window Functions:
COUNT(CASE WHEN Something = 1 THEN CustomerKey END) OVER (PARTITION BY CustomerKey ORDER BY [Date]
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) -1 AS [Count]
Old answer before new required logic:
COUNT(CustomerKey) OVER (PARTITION BY CustomerKey ORDER BY [Date]
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) -1 AS [Count]
If you're not using 2012 an alternative is to use ROW_NUMBER
ROW_NUMBER() OVER (PARTITION BY CustomerKey ORDER BY [Date]) - 1 AS Count
Using Microsoft SQL Server 2012, I am trying to create a new view that will return the real start and finish of a line when the descriptions match.
I have a table that looks like this
+----+-------+-------+-----+
| ID | desc | start | end |
+----+-------+-------+-----+
| 1 | line1 | 0 | 100 |
| 2 | line2 | 0 | 100 |
| 3 | line2 | 101 | 200 |
+----+-------+-------+-----+
I want to add 2 more columns so that when the desc matches, it returns the 0 from ID 2 and the 200 from ID 3 like this:
+----+-------+-------+-----+------------+----------+
| ID | desc | start | end | real_start | real_end |
+----+-------+-------+-----+------------+----------+
| 1 | line1 | 0 | 100 | 0 | 100 |
| 2 | line2 | 0 | 100 | 0 | 200 |
| 3 | line2 | 101 | 200 | 0 | 200 |
+----+-------+-------+-----+------------+----------+
My syntax so far:
CREATE VIEW tableview1
AS
SELECT
ID, desc,
start, end,
(???) as real_start,
(???) as real_end
FROM
linetable
WHERE
condition;
I'm at a loss as to how to group and compare the two lines when the description matches and select the lowest of the two. I'll play around on my own and update the thread.
Thanks so much!
Your sub-selects could simply be MIN()/MAX() for that desc
i think this will work, can anyone confirm?
CREATE VIEW tableview1
AS
select
t1.ID, t1.desc,
t1.start, t1.end,
(select min(start)
from linetable z
where z.desc = t1.desc) as real_start,
(select min(end)
from linetable z
where z.desc = t1.desc) as real_end
from
(SELECT
ID, desc,
start, end,
FROM
linetable
WHERE
condition) as t1
I am using SQL Server 2012 and am trying to construct a pivot table from TSQL based on the table below which has been generated by joining multiple tables.
INCIDENT ID | Department | Priority | Impact
--------------------------------------------
1 | IT | Urgent | High
2 | IT | Retrospective | Medium
3 | Marketing | Normal | Low
4 | Marketing | Normal | High
5 | Marketing | Normal | Med
6 | Finance | Normal | Med
From this table, want it to be displayed in following format:
Priority | Normal | Urgent | Retrospective |
| Department | Low | Medium | High | Low | Medium | High | Low | Medium | High |
--------------------------------------------------------------------------------
| IT | 1 | 1 | 0 | 1 | 1 | 0 | 1 | 1 | 0 |
| Finance | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 1 | 0 |
| Marketing | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 1 | 0 |
I have the following code which successfully Pivots on the "Priority" level.
SELECT *
FROM (
SELECT
COUNT(incident.incident_id) OVER(PARTITION BY serv_dept.serv_dept_n) Total,
serv_dept.serv_dept_n Department,
ImpactName.item_n Impact,
PriorityName.item_n Priority
FROM -- ommitted for brevity
WHERE -- ommitted for brevity
) AS T
PIVOT (
COUNT(Priority)
FOR Priority IN ("Normal", "Urgent", "Retrospective")
) PIV
ORDER BY Department ASC
How can I get this query to pivot on two levels like the second table I pasted?
Any help would be appreciated.
The easiest way may be conditional aggregation:
select department,
sum(case when priority = 'Normal' and target = 'Low' then 1 else 0 end) as Normal_low,
sum(case when priority = 'Normal' and target = 'Med' then 1 else 0 end) as Normal_med,
sum(case when priority = 'Normal' and target = 'High' then 1 else 0 end) as Normal_high,
. . .
from t
group by department;
I'll take a stab at it:
WITH PivotData AS
(
SELECT
Department
, Priority + '_' + Impact AS PriorityImpact
, Incident_ID
FROM
<table>
)
SELECT
Department
, Normal_Low
, Normal_Medium
,...
FROM
PivotData
PIVOT (COUNT(Incident_ID FOR PriorityImpact IN (<Listing all the PriorityImpact values>) ) as P;