Dynamic SQL Update - sql-server

I have the following SQL Server 2008 table:
ID Destination Last Result
01 (555) 319-5170 Disconnect
02 (555) 319-5170 Duplicate
03 (555) 319-5170 Duplicate
04 (555) 261-5000 Duplicate
05 (555) 261-5000 Duplicate
06 (555) 261-7325 Busy
07 (555) 261-7325 Duplicate
08 (555) 261-7345 No Answer
09 (555) 261-7345 Duplicate
My goal is to dynamically set the 'Last Result' column for all matching phone numbers. So, in the example table above for Destination((555) 319-5170), the result for all matching phone numbers(555) 319-5170) with the value 'Disconnect'. The sample update statement is below:
UPDATE C
SET [Last Result] = (
SELECT Destination
FROM Call
WHERE [Last Result] NOT IN ('Duplicate','No Phone #')
GROUP BY Destination
HAVING COUNT(Destination) > 1)
FROM Call C
INNER JOIN
(
SELECT Destination
FROM Call
WHERE [Last Result] NOT IN ('Duplicate','No Phone #')
GROUP BY Destination
HAVING COUNT(Destination) > 1
) Dup ON Dup.Destination = C.Destination
WHERE C.[Last Result] NOT IN ('Duplicate','No Phone #')
But I am getting an error:
Msg 512, Level 16, State 1, Line 1
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
**EXPECTED OUTPUT**:
ID Destination Last Result
01 (555) 319-5170 Disconnect
02 (555) 319-5170 Disconnect
03 (555) 319-5170 Disconnect
04 (555) 261-5000 Duplicate
05 (555) 261-5000 Duplicate
06 (555) 261-7325 Busy
07 (555) 261-7325 Busy
08 (555) 261-7345 No Answer
09 (555) 261-7345 No Answer
Thanks in advance for any assistance with a possible solution.

You can look up the first Last Result with the row_number() window function. However, there has to be a way to define "first". In the example, I'm assuming you have an identity column:
update t1
set [Last Result] = t2.[Last Result]
from Table1 t1
join (
select row_number() over (partition by Destination
order by Id) as rn
, *
from Table1
) t2
on t1.Destination = t2.Destination
and t2.rn = 1;
Example at SQL Fiddle.
If you do not have an identity column, please update the question with how you define "first". There could be a CreateDt column for example.

Related

Joining three tables with OVER, for accumulative monthly figures

I have made the amendments as per comments and entered here as not enough characters allowed in comments. I think there may be a few issues on the OVER and with the JOIN. Updated query:
SELECT RIGHT('0' + CAST(day(oh_datetime) AS VARCHAR (2)), 2),
SUM(SUM((CASE oh_sot_id WHEN 1 THEN 1 WHEN 4 THEN -1 END) * oht_net)) over (ORDER BY day(oh_datetime) ROWS UNBOUNDED PRECEDING) AS 'Orders In($)',
SUM((CASE oh_cd_id WHEN 11728 THEN 1 END) * oht_net) AS 'Target($)',
SUM(SUM((CASE ih_credit WHEN 'false' THEN 1 WHEN 'true' THEN -1 END) * ih_net)) over (ORDER BY day(ih_datetime) ROWS UNBOUNDED PRECEDING) AS 'Sales($)'
FROM order_header_total
JOIN order_header ON order_header_total.oht_oh_id = order_header.oh_id
JOIN invoice_header ON order_header.oh_id = invoice_header.ih_oh_id
WHERE oh_datetime >= DATEADD(day, 1, EOMONTH(GETDATE(), -1)) AND oh_datetime < DATEADD(day, 1, EOMONTH(GETDATE()))
GROUP BY day(oh_datetime), day(ih_datetime)
UNION SELECT 'YAxis','0','0','0'
Table should display:
Date
Orders In
Target
Sales
01
6402.19
12321.57
128539.13
02
17795.94
24643.14
148258.63
03
50703.09
36964.71
171231.14
04
116034.29
49286.28
188157.69
28
353989.36
345004.00
446808.05
I have not done the full month for sake of space, but included the last day to show how it should accumulate. Instead it looks like this:
Date
Orders In
Target
Sales
01
5507.32
5507.32
01
5833.52
5833.52
01
6402.19
29377.18
02
10312.35
188157.69
02
16592.09
16023.42
02
17795.94
54950.68
03
30439.28
28666.76
03
30581.03
28808.51
04
36029.72
24700.77
04
37082.36
38767.55
23
144191.70
143992.45
Again a selection of data and then showing the last row for the sake of space. The date is not grouping, 'Orders In' and 'Sales' are not accumulating, and there is no data displaying for 'Target'.

Convert Column values of a single row into 2 columns with the column headers in SQL Server

I need to convert Column and a row into 2 columns.
Below is the sample Table [Table01] with 4 columns and a single row.
First Second Third Forth
01 02 03 04
I need to Transpose it as a new table [Table01_T]
Column01 Column02
First 01
Second 02
Third 03
Forth 04
Every time we receive a single row with 4 columns and we need them to convert in 2 columns and four rows.
Something like this
select
v.*
from [Table01]
cross apply
(values ('First', [First]),('Second',[Second]),
('Third',[Third]),('Forth',[Forth])) v(Column01, Column02);
Using the same sample data this query produces the same results. I find this syntax to be more readable then UNPIVOT.
Results
Column1 Column02
First 01
Second 02
Third 03
Forth 04
You can use UNPIVOT:
SELECT Column01, Column02
-- INTO dbo.Table01_T
FROM dbo.Table01
UNPIVOT
( -- vvvvv column names you want to turn to rows
Column02 FOR Column01 IN ([First],[Second],[Third],[Fourth])
-- ^^^^^^^^ becomes column name from each original column
-- ^^^^^^^^ becomes column value from each original column
) AS u;
Isolated example using a table variable:
DECLARE #x table([First] char(2),Second char(2),Third char(2),Fourth char(2));
INSERT #x([First],[Second],[Third],[Fourth]) VALUES ('01','02','03','04');
SELECT Column01, Column02
FROM #x UNPIVOT
(
Column02 FOR Column01 IN ([First],[Second],[Third],[Fourth])
) AS u;
Results:
Column01 Column02
-------- --------
First 01
Second 02
Third 03
Fourth 04
Working fiddle

How to join tables when there are duplicates in right table

I have three tables. Table Cust has a custID field, plus various other values (name, address etc)
Table List has a single column ID. Each ID is a custID in the Cust table
Edit: the purpose of this is to filter the records, restricting thge results to ones where the CustID appears in the list table.
All three tables are indexed.
Table Trans has a TransactionID field, a Cust field that holds a customer ID, And other transaction fields
Edit: I should have mentioned that in some cases there will be no transaction record. In this case I want one row of Customer info with the transaction fields null or blank.
I want a query to return cust and transaction ID for each ID in the list table. If there is more than one matching row in the transaction table, I want each included along 3with the matching cust info. So if the tables look like This:
Cust
ID Name
01 John
02 Mary
03 Mike
04 Jane
05 Sue
06 Frank
List
ID
01
03
05
06
Transact
TransID CustId Msg
21 01 There
22 01 is
23 02 a
24 03 tide
25 04 in
26 04 the
27 05 affairs
28 05 of
29 05 men
I want the result set to be:
CustID Name TransID Msg
01 John 21 There
01 John 22 is
03 Mike 24 tide
05 Sue 27 affairs
05 Sue 28 of
05 Sue 29 men
06 Frank -- --
(Where -- represents NULL or BLANK)
Obviously the actual tables are much larger (millions of rows), but that shows the pattern, one row for every item in table Transactions that matches any of the items in the List table, with matching fields from the Cust table. if there is no matching Transaction, one row of customer info from each ID in the List table. CustID is unique in the Cust and List tables, but not in the transaction table.
This needs to work on any version of SQL server from 2005 onward, if that matters.
Any suggestions?
Unless I'm missing something, this is all you need to do:
Select T.CustID, C.Name, T.TransID, T.Msg
From Transact T
Join Cust C On C.Id = T.CustId
Join List L On L.Id = C.Id
Order By T.CustID, T.TransID
;with cust (id, name) as
(
select 1, 'John' union all
select 2, 'Mary' union all
select 3, 'Mike' union all
select 4, 'Jane' union all
select 5, 'Sue'
), list (id) as
(
select 1 union all
select 3 union all
select 5
), transact (TransId, CustId, Msg) as
(
select 21, 1, 'There '
union all select 22, 1, 'is'
union all select 23, 2, 'a'
union all select 24, 3, 'tide'
union all select 25, 4, 'in'
union all select 26, 4, 'the'
union all select 27, 5, 'affairs'
union all select 28, 5, 'of'
union all select 29, 5, 'men'
)
select
CustId = c.id,
Name = c.Name,
TransId = t.TransId,
Msg = t.Msg
from cust c
inner join list l
on c.id = l.id
inner join transact t
on l.id = t.custid
yields:
CustId Name TransId Msg
----------- ---- ----------- -------
1 John 21 There
1 John 22 is
3 Mike 24 tide
5 Sue 27 affairs
5 Sue 28 of
5 Sue 29 men

sql query to calculate the time difference between the two successive rows

Can anyone help me to calculate the time difference(in hh:mm) between the two rows, when the Procs_ID changes from 01 to another Procs_ID.
Procs_ID meter_id date
01 0000012 2015-10-12 09:07:22.530
03 0000013 2015-10-12 09:11:51.733
01 0000014 2015-10-12 09:12:38.550
02 0000015 2015-10-12 10:38:52.923
03 0000016 2015-10-12 10:40:33.467
01 0000017 2015-10-12 10:40:56.013
Thanks in advance
Here is an example with LEAD which is avaliable for SQL Server 2012+
select
*,
case
when Procs_Id = '01'
and lead(Procs_ID) over (order by [date]) <> Procs_ID then datediff(mi,[date],lead([date]) over (order by [date]))
end as TimeDiffInMin
from YourTable

Looking for missing rows T-SQL

I am having an issue and I have been working on it for the past three hours or so and have not found a solution. Running on a SQL Server platform. I have a single table that looks like this.
PT ITM VAL
-- --- ---
01 01 A
01 02 B
01 03 C
02 01 A
02 03 C
03 01 A
03 02 B
I am trying to find which PTs are missing the item numbers.
In the case above PT02 and PT03 are missing two item. This is the base what where I started, but I am not sure if I am even on the right track.
select t.PT,t.ITM
FROM MYTABLE t
GROUP BY t.PT,t.ITM
HAVING COUNT(*) > 1
Thanks
jlimited
If you're expecting 3 ITM per PT, the query would be
select PT
FROM MYTABLE
GROUP BY PT
HAVING COUNT(ITM) < 3
for other conditions a more complicated query is required.
Here was the solution that worked. I had to select a VAL that was populated, to find the values that were not.
select stg.PT,COUNT(stg.ITM) AS ITM_CNT
FROM MYTABLE stg
WHERE stg.ITM IS NOT NULL
AND stg.VAL IN (11)
GROUP BY stg.PT
HAVING COUNT(stg.ITM) > 1
EXCEPT
select stg.PT,COUNT(stg.ITM) AS ITM_CNT
FROM MYTABLE stg
WHERE stg.ITM IS NOT NULL
AND stg.VLA IN (4,5)
GROUP BY stg.PT
HAVING COUNT(stg.ITM) > 1

Resources