Related
There is a table called 'member' which has 60 columns. Only some of the columns have values; 5 columns have values and the rest of 55 columns are NULL.
The problem is that the columns with values are scattered and I find it difficult to search the row to find the ones which have values.
I have tried a few suggestions which I received while posting this question. Below is one of them.
select * from table order by NULLIF(value,'') = '' DESC, value
I tried below
select * from member order by NULLIF(date_of_begin,'')
This doesn't satisfy my requirement when I want something like this. I use a select statement and segregate all columns having values to be displayed first and then all columns with NULL displayed last.
ID Member Name Age Gender Date of begin DOB DOC Extra
1 John 34 M 4/10/2019 NULL NULL NULL
2 Jack NULL M 4/11/2019 NULL NULL NULL
3 David 54 M 4/15/2019 NULL NULL NULL
4 Eric NULL M 4/16/2019 NULL NULL NULL
5 Ivan 45 M 4/10/2019 NULL NULL NULL
I want a select statement which will divide the above example with the below grouping. Age is NULL for Jack, so it should be placed in last column and displayed. This will make my work easier in finding which columns have NULL and which have values sorted.
For example-- >
Select * from member where id =2 IS NOT NULL (I need help here in this statement change)
Desired results:
ID Member Name Gender Date of begin DOB DOC Extra Age
2 Jack M 4/11/2019 NULL NULL NULL NULL
I'm not willing to swear this is worth the effort, but if you only need one ID at a time, or at least only a few, this will return only the non-null column values. If you wanted to go to even greater pain and try to pivot it back into rows, have at it, but this gets you a workable result set.
We're using CROSS APPLY to unpivot your results, and then dispose of the NULL values. You're data doesn't look like a row anymore, but the handful of data points you need are there for you.
Using the CROSS APPLY, in order to get all of the column values into one single column, I CAST them all as NVARCHAR data, so your results are all text fields.
In the example, I returned two ID values, just so you could see how that would look.
Data set up, in case anybody else wants to take a swing at this:
DECLARE #table TABLE(
ID INTEGER NOT NULL PRIMARY KEY
,Member_Name VARCHAR(5) NULL
,Age INTEGER NULL
,Gender VARCHAR(1) NULL
,Date_of_begin DATE NOT NULL
,DOB VARCHAR(4) NULL
,DOC VARCHAR(4) NULL
,Extra VARCHAR(4) NULL
);
INSERT INTO #table(ID,Member_Name,Age,Gender,Date_of_begin,DOB,DOC,Extra) VALUES (1,'John',34,'M','4/10/2019',NULL,NULL,NULL);
INSERT INTO #table(ID,Member_Name,Age,Gender,Date_of_begin,DOB,DOC,Extra) VALUES (2,'Jack',NULL,'M','4/11/2019',NULL,NULL,NULL);
INSERT INTO #table(ID,Member_Name,Age,Gender,Date_of_begin,DOB,DOC,Extra) VALUES (3,'David',54,'M','4/15/2019',NULL,NULL,NULL);
INSERT INTO #table(ID,Member_Name,Age,Gender,Date_of_begin,DOB,DOC,Extra) VALUES (4,'Eric',NULL,'M','4/16/2019',NULL,NULL,NULL);
INSERT INTO #table(ID,Member_Name,Age,Gender,Date_of_begin,DOB,DOC,Extra) VALUES (5,'Ivan',45,'M','4/10/2019',NULL,NULL,NULL);
Here's the query.
SELECT
c.*
FROM #table AS t
CROSS APPLY (VALUES ('ID',CAST(t.ID AS NVARCHAR(30))),
('Member_Name',CAST(t.Member_Name AS NVARCHAR(30))),
('Age',CAST(t.Age AS NVARCHAR(30))),
('Gender',CAST(t.Gender AS NVARCHAR(30))),
('Date_of_begin',CAST(t.Date_of_begin AS NVARCHAR(30))),
('DOB',CAST(t.DOB AS NVARCHAR(30))),
('DOC',CAST(t.DOC AS NVARCHAR(30))),
('Extra',CAST(t.Extra AS NVARCHAR(30)))
) c (ColName,ColValue)
WHERE t.ID IN (2,3)
AND c.ColValue IS NOT NULL
ORDER BY
t.ID,
CASE
WHEN c.ColName = 'ID' THEN 1
WHEN c.ColName = 'Member_Name' THEN 2
ELSE 3
END
Results:
+---------------+------------+
| ColName | ColValue |
+---------------+------------+
| ID | 2 |
| Member_Name | Jack |
| Gender | M |
| Date_of_begin | 2019-04-11 |
| ID | 3 |
| Member_Name | David |
| Age | 54 |
| Gender | M |
| Date_of_begin | 2019-04-15 |
+---------------+------------+
The solution I suggest is to store one record in n rows,
n is the number of columns,
then you can order the result as you wish using order by
or add the criteria based on NULL values
I am using the system sql server tables syscolumns and sysobjects
create table tab_mytable (id int ,colonne varchar(100),valeur varchar(100));
insert into tab_mytable(id,colonne) select c.colid,c.name from sysobjects o inner join
syscolumns c on o.id=c.id where o.name='member' order by c.colid
declare #cmd as varchar(1000)
declare #mytab as table (val varchar(100))
declare mycursor cursor for select colonne from tab_mytable
declare #colonne as varchar(100)
declare #val as varchar(100)
open mycursor
fetch mycursor into #colonne
while ##fetch_status=0
begin
set #cmd= 'select '+#colonne +' from member where id=2'
insert into #mytab exec(#cmd)
select #val=val from #mytab
set #cmd='update tab_mytable set valeur='''+#val+''' where colonne='''+#colonne+''''
exec(#cmd)
print #cmd
delete from #mytab
fetch mycursor into #colonne
end
close mycursor
deallocate mycursor
--Put here your Query to display teh results as you wish
select * from tab_mytable order by valeur
You can use also the UNPIVOT statement
But in that use you have to write all the column names, for the solution above, you won't write them in your script
My problem is that I created a query that takes too long to execute.
City | Department | Employee | Attendance Date | Attendance Status
------------------------------------------------------------------------
C1 | Dept 1 | Emp 1 | 2016-01-01 | ABSENT
C1 | Dept 1 | Emp 2 | 2016-01-01 | LATE
C1 | Dept 2 | Emp 3 | 2016-01-01 | VACANCY
So I want to create a view that contains same data and adds a column that contains the total number of employees (that serves me later in a SSRS project to determine the percentage of each status).
So I created a function that makes simple select filtering by department and date.
and this is the query that uses the function:
SELECT City, Department, Employee, [Attendence Date], [Attendance Status], [Get Department Employees By Date](Department, [Attendence Date]) AS TOTAL
FROM attendenceTable
This is the function:
CREATE FUNCTION [dbo].[Get Department Employees By Date]
(
#deptID int = null,
#date datetime = null
)
RETURNS nvarchar(max)
AS
BEGIN
declare #result int = 0;
select #result = count(*) from attendenceTable where DEPT_ID = #deptID and ATT_DATE_G = #date;
RETURN #result;
END
The problem is that query takes too long (I mean very long time) to execute.
Any Suggestion of optimization?
Your function is a scalar function, which is run once for every row in the result set (~600,000) times, and is a known performance killer. It can be rewritten into an inline table-valued function, or if the logic is not required elsewhere, a simple group, count & join would suffice:
WITH EmployeesPerDeptPerDate
AS ( SELECT DEPT_ID ,
ATT_DATE_G ,
COUNT(DISTINCT Employee) AS EmployeeCount
FROM attendenceTable
GROUP BY DEPT_ID ,
ATT_DATE_G
)
SELECT A.City ,
A.Department ,
A.Employee ,
A.[Attendence Date] ,
A.[Attendance Status] ,
ISNULL(B.EmployeeCount, 0) AS EmployeeCount
FROM attendenceTable AS A
LEFT OUTER JOIN EmployeesPerDeptPerDate AS B ON A.DEPT_ID = B.DEPT_ID
AND A.ATT_DATE_G = B.ATT_DATE_G;
I'm working with SQL Server 2005 and looking to export some data off of a table I have. However, prior to do that I need to update a status column based upon a field called "VisitNumber", which can contain multiple entries same value entries. I have a table set up in the following manner. There are more columns to it, but I am just putting in what's relevant to my issue
ID Name MyReport VisitNumber DateTimeStamp Status
-- --------- -------- ----------- ----------------------- ------
1 Test John Test123 123 2014-01-01 05.00.00.000
2 Test John Test456 123 2014-01-01 07.00.00.000
3 Test Sue Test123 555 2014-01-02 08.00.00.000
4 Test Ann Test123 888 2014-01-02 09.00.00.000
5 Test Ann Test456 888 2014-01-02 10.00.00.000
6 Test Ann Test789 888 2014-01-02 11.00.00.000
Field Notes
ID column is a unique ID in incremental numbers
MyReport is a text value and can actually be thousands of characters. Shortened for simplicity. In my scenario the text would be completely different
Rest of fields are varchar
My Goal
I need to address putting in a status of "F" for two conditions:
* If there is only one VisitNumber, update the status column of "F"
* If there is more than one visit number, only put "F" for the one based upon the earliest timestamp. For the other ones, put in a status of "A"
So going back to my table, here is the expectation
ID Name MyReport VisitNumber DateTimeStamp Status
-- --------- -------- ----------- ----------------------- ------
1 Test John Test123 123 2014-01-01 05.00.00.000 F
2 Test John Test456 123 2014-01-01 07.00.00.000 A
3 Test Sue Test123 555 2014-01-02 08.00.00.000 F
4 Test Ann Test123 888 2014-01-02 09.00.00.000 F
5 Test Ann Test456 888 2014-01-02 10.00.00.000 A
6 Test Ann Test789 888 2014-01-02 11.00.00.000 A
I was thinking I could handle this by splitting each types of duplicates/triplicates+ (2,3,4,5). Then updating every other (or every 3,4,5 rows). Then delete those from the original table and combine them together to export the data in SSIS. But I am thinking there is a much more efficient way of handling it.
Any thoughts? I can accomplish this by updating the table directly in SQL for this status column and then export normally through SSIS. Or if there is some way I can manipulate the column for the exact conditions I need, I can do it all in SSIS. I am just not sure how to proceed with this.
WITH cte AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY VisitNumber ORDER BY DateTimeStamp) rn from MyTable
)
UPDATE cte
SET [status] = (CASE WHEN rn = 1 THEN 'F' ELSE 'A' END)
I put together a test script to check the results. For your purposes, use the update statements and replace the temp table with your table name.
create table #temp1 (id int, [name] varchar(50), myreport varchar(50), visitnumber varchar(50), dts datetime, [status] varchar(1))
insert into #temp1 (id,[name],myreport,visitnumber, dts) values (1,'Test John','Test123','123','2014-01-01 05:00')
insert into #temp1 (id,[name],myreport,visitnumber, dts) values (2,'Test John','Test456','123','2014-01-01 07:00')
insert into #temp1 (id,[name],myreport,visitnumber, dts) values (3,'Test Sue','Test123','555','2014-01-01 08:00')
insert into #temp1 (id,[name],myreport,visitnumber, dts) values (4,'Test Ann','Test123','888','2014-01-01 09:00')
insert into #temp1 (id,[name],myreport,visitnumber, dts) values (5,'Test Ann','Test456','888','2014-01-01 10:00')
insert into #temp1 (id,[name],myreport,visitnumber, dts) values (6,'Test Ann','Test789','888','2014-01-01 11:00')
select * from #temp1;
update #temp1 set status = 'F'
where id in (
select id from #temp1 t1
join (select min(dts) as mindts, visitnumber
from #temp1
group by visitNumber) t2
on t1.visitnumber = t2.visitnumber
and t1.dts = t2.mindts)
update #temp1 set status = 'A'
where id not in (
select id from #temp1 t1
join (select min(dts) as mindts, visitnumber
from #temp1
group by visitNumber) t2
on t1.visitnumber = t2.visitnumber
and t1.dts = t2.mindts)
select * from #temp1;
drop table #temp1
Hope this helps
I need some advice.
I have a column with nulls in a field at a particular time period.
Name Date
----- -----
Cat 1/1/2012
Dog 1/2/2012
Fish 1/3/2012
NULL 1/4/2012
Goat 1/5/2012
NULL 1/6/2012
Sheep 1/7/2012
In the example above, how would I write a SQL statement to select the last known value for column Name whenever there is a null value in the column?
For instance I'd like the table to look like this:
Name Date
----- -----
Cat 1/1/2012
Dog 1/2/2012
Fish 1/3/2012
Fish 1/4/2012
Goat 1/5/2012
Goat 1/6/2012
Sheep 1/7/2012
Would this pseudo-code work?
Select
isnull(Name, "Select Name from Table where Date = GetDate() - 1")
,Date
From Table
Try this [v is original, v2 is calculated new value] :
DECLARE #table table(v varchar(10), d varchar(10))
INSERT INTO #table
SELECT 'Cat','1/1/2012' UNION
SELECT 'Dog','1/2/2012' UNION
SELECT 'Fish','1/3/2012' UNION
SELECT NULL,'1/4/2012' UNION
SELECT 'Goat','1/5/2012' UNION
SELECT NULL,'1/6/2012' UNION
SELECT 'Sheep','1/7/2012'
SELECT A.v, A.d, ISNULL(A.v,B.v) V2
FROM #table A
OUTER APPLY ( SELECT TOP 1 *
FROM #table
WHERE d < A.d
AND v IS NOT NULL
ORDER BY d desc) B
order by d
I have a table that keeps track of transactions for various accounts:
AccountTransactions
AccountTransactionID int NOT NULL (PK)
AccountID int NOT NULL (FK)
Amount decimal NOT NULL
Upon inserting a record with a negative amount into this table, I need to verify that the SUM of the amount column for the specified account is greater than zero. If the new record will cause this SUM to fall below zero, the record should not be inserted.
For example, if I have the following records, inserting an amount of -8.00 for AccountID 5 should not be allowed:
AccountTransactionID AccountID Amount
---------------------------------------------
1 5 10.00
2 6 15.00
3 5 -3.00
What is the best method to accomplish this? Check constraint, trigger, or just check for this condition in a stored procedure?
You can do a simple check:
DECLARE #TheSum decimal(18,2)
SET #TheSum = (SELECT SUM(MyCol) FROM MyTable WHERE AccountID = #SomeParameter)
If #TheSum > 0
BEGIN
--do your insert
END
...
You could add a where clause to your insert:
insert YourTable
(AccountID, Amount)
select #AccountID, #Amount
where 0 <=
(
select #Amount + sum(Amount)
from YourTable
where AccountID = #AccountID
)