Access Concatenating Values in a Query - sql

I have a query, [Query1], with employee names, projects, days, months, and years.
In another query, [Query2], I take all the values and put them into a cross table. My rows are "Year, Month, Employee." My column is "Day." My values are Projects.
The problem is that for one date, there may be more than one project assigned to an employee.
When I attempt to put the projects as values into a table using IIf(Count(*)>0,[Project],""), I get an error because there may be more than one possible value for the project, and access doesn't know which one to choose.
I need a way to Concatenate the values if there is more than one Project.
Ex:
[Query1]
Bill | CC555 | 28 | 03 | 2014
Jim | CC999 | 29 | 03 | 2014
Jim | CC555 | 29 | 03 | 2014
John | CC555 | 29 | 03 | 2014
[Query2]
Year | Month | Employee | 1 | 2 | 3 | ... | 27 | 28 | 29 | 30 | 31
2014 | 03 | Bill | - | - | - | ... | - | CC555 | - | - | -
2014 | 03 | Jim | - | - | - | ... | - | - | CC555 + CC999 | - | -
2014 | 03 | John | - | - | - | ... | - | - | CC555 | - | -
Aside: [Query1] is dynamic and could have duplicate dates deleted or added to it, so [Query2] values must change accordingly.

one simple example,you have to make it dynamic,in real scenrio no need of table variable or CTE if using dynamic sql.i think no need of dynamic,just hard code from 1 to 31
;With CTE as
(
select 'Bill' Employee ,'CC555' codes,28 dd,03 mm ,2014 yrs union all
select 'Jim ','CC999', 29 , 03 , 2014 union all
select 'Jim ','CC555', 29 , 03 , 2014 union all
select 'John','CC555', 29 , 03 , 2014
)
select yrs,mm,Employee,isnull([28],'-')[28],[29],[30] from
(select Employee,dd,mm,yrs
,stuff((select ','+codes from cte b where b.Employee=a.Employee for xml path('')),1,1,'')codes
from cte a ) src
pivot (min(codes) for dd in([28],[29],[30])) pvt

By using the function given here allenbrowne.com/func-concat.html, and following the example given here http://www.access-programmers.co.uk/forums/showthread.php?t=234291, I was able to solve the problem.

Related

SQL Server 2019. Need to update particular column in particular row

I have table like this:
LinN | RecType | Value
-----+---------+--------
1 | 01 | 12345
2 | 02 | Null
3 | 03 | Null
4 | 05 | Null
6 | 01 | 67890
7 | 02 | Null
8 | 09 | Null
I need to make it look like this:
LinN | RecType | Value
-----+---------+--------
1 | 01 | 12345
2 | 02 | 12345
3 | 03 | 12345
4 | 05 | 12345
6 | 01 | 67890
7 | 02 | 67890
8 | 09 | 67890
I tried a cursor, Lead and Lag - but nothing is working for me.
Any idea/help will be highly appreciated
You can use a cumulative max:
select LinN, RecType, Value,
max(value) over (order by try_convert(int, LinN)) as imputed_value
from t;
You can incorporate this into an update:
with toupdate as (
select LinN, RecType, Value, max(value) over (order by LinN) as imputed_value
from t
)
update toupdate
set value = imputed_value;
Moderators, please close this discussion. I do not see any reason to keep it active.
Thank you everybody for your time.

PostgreSQL calculate difference between multi rows

I tried to calculate difference between rows in a field using a query:
Illustrations:
input:year,month,name, size
output:increase
year | month | name | Size | increase
------+--------+------- -+-------+-----------
2020 | 01 | john |10 | 0
2020 | 01 | peter |12 | 0
2020 | 01 | kim |16 | 0
2020 | 02 | john |15 | 5 <- 15 - 10
2020 | 02 | peter |16 | 4 <- 16 - 12
2020 | 02 | kim |17 | 1 <- 17 - 16
2020 | 03 | john |18 | 3 <- 18 - 16
2020 | 03 | peter |19 | 3 <- 19 - 16
2020 | 03 | kim |77 | 60 <- 77 - 17
-------
2020 | 12 | john |25 | 17
2020 | 12 | peter |70 | 33
2020 | 12 | kim |90 |42
Increase column as output by difference between adjacent "name" rows in size.
Use LAG()
select year,
month,
name,
size,
size - lag(size) over (partition by name order by year, month) as increase
from MyTable
If you want 0s for the first set of rows, then use the 3-argument form of lag():
select year, month, name, size,
(size - lag(size, 1, size)) over (partition by name order by year, month) as increase
from MyTable;
Personally, I prefer NULL so I prefer JohnHC's answer. However, the question is explicitly asking for 0 values there.
Thanks JohnHC and Gorden for helping.
It works when I run the query on psql commandline. But when I put it into a php script:
$result = pg_query($conn,"select year, month, name, (size - lag(size, 1, size)) over (partition by name order by year, month). as increase from testdb ");
I get error message:
PHP Warning: pg_query(): Query failed: ERROR: syntax error at or near '- lag(size)......'

SELECT Top values for each records

I have been battling through this query/query design for sometime now and I thought it's time to ask the experts! Here's my table results:
ID | Status | date |
---------------------------------
05 | Returned | 20/6/2018 |
03 | Sent | 12/5/2018 |
01 | Pending | 07/6/2018 |
01 | Engaged | 11/4/2018 |
03 | Contacted | 16/4/2018 |
05 | Surveyed | 04/3/2017 |
05 | No Contact | 05/3/2017 |
How do I get it to return top/newest value for each ID:
ID | Status | date |
---------------------------------
05 | Returned | 20/6/2018 |
03 | Sent | 12/5/2018 |
01 | Pending | 07/6/2018 |
I've tried group by, TOP 1, Distinct and results still not what I wanted. Also, displaying the results by top 5% is won't do either as the ID can be more than just 3 types.
My QUERY below:
INSERT INTO TmpAllcomsEmployee ( StatusID, EmployeeID, CommunicationDate )
SELECT DISTINCT CommunicationLog.StatusID, TmpAllcomsEmployee.EmployeeID,
Max(CommunicationLog.CommunicationDate) AS MaxOfCommunicationDate
FROM CommunicationLog RIGHT JOIN TmpAllcomsEmployee ON
CommunicationLog.EmployeeID = TmpAllcomsEmployee.EmployeeID
GROUP BY CommunicationLog.StatusID, TmpAllcomsEmployee.EmployeeID
ORDER BY Max(CommunicationLog.CommunicationDate) DESC;
One method is a correlated subquery:
select cl.*
from CommunicationLog as cl
where cl.date = (select max(cl2.date)
from CommunicationLog as cl2
where cl2.EmployeeID = cl.EmployeeID
);
This gets the most recent record for each employee in CommunicationLog. You can join in the other table if you really need it. It does not seem unnecessary unless you are using it for filtering.

SQL - Adding an avg column to a detail table

I'm on Teradata. I have an order table like the below.
custID | orderID | month | order_amount
-----------------------------------------
1 | 1 | jan | 10
1 | 2 | jan | 20
1 | 3 | feb | 5
1 | 4 | feb | 7
2 | 5 | mar | 20
2 | 6 | apr | 30
I'd like to add a column to the above table called "Avg order amount per month per customer". Since the table is at an order level, adding this column will cause duplicates like the below, which is ok.
custID | orderID | month | order_amount | avgOrdAmtperMonth
-------------------------------------------------------------
1 | 1 | jan | 10 | 15
1 | 2 | jan | 20 | 15
1 | 3 | feb | 5 | 6
1 | 4 | feb | 7 | 6
2 | 5 | mar | 20 | 20
2 | 6 | apr | 30 | 30
I want the output to have all the columns above, not just the custid and the new column. I'm not sure how to write this because one part of the table is an at order level and the new column needs to be grouped by customer+month. How would I do this?
This is a simple group average:
AVG(order_amount) OVER (PARTITION BY custID, month)
Why not just do the calculation when you query the table?
select t.*,
avg(order_amount) over (partition by custId, month) as avgOrderAmtPerMonth
from t;
You can add this into a view if you want to make it available to multiple downstream queries.
Actually adding the column to the table is a maintenance "nightmare". You have to add triggers to the table and update the value for updates, inserts, and deletes.

SQL - How do I query for re-admissions in TSQL?

I'm trying to figure out how to query for readmissions on Server 2008r2. Here is the basic structure of the visit table. There are other fields but none that I thought would be helpful. One issue is that some of these may be transfers instead of discharges which I have no easy way to deduce but that issue can be ignored for now. I tried my hand at this but I guess my understanding of SQL needs more work. I tried to find any info I could online but none of the queries lead me to a useful conclusion or I just didn't understand. Any suggestions would be appreciated.
EDIT: Readmission is if a patient returns within 30 days of previous discharge.
+---------+--------+-----------------+-----------------+
| VisitID | UID | AdmitDT | DischargeDT |
+---------+--------+-----------------+-----------------+
| 12 | 2 | 6/17/2013 6:51 | 6/17/2013 6:51 |
| 16 | 3 | 6/19/2013 4:48 | 6/21/2013 13:35 |
| 18 | 3 | 6/11/2013 12:08 | 6/11/2013 12:08 |
| 21 | 3 | 6/12/2013 14:40 | 6/12/2013 14:40 |
| 22 | 3 | 6/13/2013 10:00 | 6/14/2013 12:00 |
| 25 | 2 | 6/11/2013 16:13 | 6/11/2013 16:13 |
| 30 | 1 | 6/20/2013 8:35 | 6/20/2013 8:35 |
| 31 | 7 | 6/13/2013 6:12 | 6/13/2013 6:12 |
| 34 | 3 | 6/12/2013 8:40 | NULL |
| 35 | 1 | 6/12/2013 8:52 | NULL |
| 38 | 2 | 6/12/2013 10:10 | 6/12/2013 10:10 |
+---------+--------+-----------------+-----------------+
Attempt at Code:
SELECT N2.*
FROM visitTable AS N1
INNER JOIN
visitTable AS N2 ON N1.UID = N2.UID
WHERE N1.EncounterID <> N2.EncounterID AND ( N2.AdmitDT BETWEEN N1.DischargeDT and DATEADD(DD,30, N1.DischargeDT))
Here's a start:
sqlfiddle
new fiddle
It gets each visit for each UID in order of admitDT, then pairs each visit with the next visit in that result. If the current admit date is between the last discharge date and 30 days from then, select it. There are some weird points though - UID 1 is shown to have been admitted on 6/12/2012 and never discharged, but then admitted again on 6/20/2013 and discharged the same day.
edit: restructured a bit to reduce the number of joins
WITH cte AS (
SELECT visitid,uid,dischargedt,admitdt,
row_number()over(partition BY uid ORDER BY admitdt) AS r
FROM t
)
SELECT
c1.visitid AS v1, c2.visitid AS v2,
c1.uid,
c1.dischargedt as [Discharged from first visit],
c2.admitdt as [Admitted to next visit]
FROM cte c1
INNER JOIN cte c2 ON c1.uid=c2.uid
WHERE c1.visitid<>c2.visitid
AND c1.r+1=c2.r
AND c2.admitdt BETWEEN c1.dischargedt AND dateadd(d,30,c1.dischargedt )
ORDER BY c1.uid
Results:
| V1 | V2 | UID | DISCHARGED FROM FIRST VISIT | ADMITTED TO NEXT VISIT |
|----|----|-----|-----------------------------|-----------------------------|
| 25 | 38 | 2 | June, 11 2013 16:13:00+0000 | June, 12 2013 10:10:00+0000 |
| 38 | 12 | 2 | June, 12 2013 10:10:00+0000 | June, 17 2013 06:51:00+0000 |
| 18 | 34 | 3 | June, 11 2013 12:08:00+0000 | June, 12 2013 08:40:00+0000 |
| 21 | 22 | 3 | June, 12 2013 14:40:00+0000 | June, 13 2013 10:00:00+0000 |
| 22 | 16 | 3 | June, 14 2013 12:00:00+0000 | June, 19 2013 04:48:00+0000 |
try this: (Show me the visits where the admission date is after discharge for another earlier visit by the same patient)
Select * From visits v
Where Exists (Select * From Visits
Where uid = v.uid
and v.AdmitDT > DischargeDT)
You have not explained any business rules so I'll take a guess. A readmission is when multiple UID appear, and it is every record except the first one
Here is another method using windowing functions.
SELECT VT.*
FROM visitTable VT
INNER JOIN
(
SELECT VisitID, ROW_NUMBER() OVER (PARTITION BY UID ORDER BY AdmitDT) VisitCount
FROM visitTable
) RA
ON RA.VisitCount > 1 AND RA.VisitID = VT.VisitID