Presenting hierarchical data with different conditions using joins in SQL Server 2012 - tsql

I have two tables. In one table my raw data and in other table the relationships as below
Declare #Emp table(EmpId int,EmpName Varchar(100),CITY VARCHAR(100),Designation Varchar(100),ReportingManager Int)
INSERT INTO #Emp
VALUES(1,'Ram','Hyderabad','TL',6)
,(2,'Laxman','Hyderabad','TL',9)
,(3,'Suresh','Bangalore','Officer',6)
,(4,'Rajesh','Bangalore','Officer',9)
,(5,'Lokesh','Delhi','TL',6)
,(6,'Venkatesh','Mumbai','Manager',6)
,(7,'Subbu','Patna','Officer',9)
,(8,'Ravi','Hyderabad','Officer',9)
,(9,'Sai','Hyderabad','Manager',9)
,(10,'Satish','Hyderabad','Officer',6)
DECLARE #EmpRelation TABLE(EmpRelationShipID INT IDENTITY NOT NULL,ReportingTo INT,EmpID INT)
INSERT INTO #EmpRelation
VALUES(1,6)
,(2,9)
,(3,1)
,(4,5)
,(5,6)
,(7,2)
,(8,5)
,(10,1)
Here the ReportingManager Column in #Emp table indicates that If Emp
reports TL, then the TL's ManagerName.
Here ReportingTo Column in #EmpRelation indicates to whom he is
reporting.(TL or Manager).
Officers reports to TLs and TLs reports to Managers.
To get the result the have the below query which is working good
SELECT E.EmpId
,E.EmpName
,CASE
WHEN E.EmpId = E.ReportingManager
THEN 1
ELSE 0
END AS IsManager
,CASE
WHEN EXISTS (
SELECT NULL
FROM #EmpRelation ER
WHERE ER.ReportingTo = E.EmpId
)
THEN 1
ELSE 0
END AS HasSubordinates
,CASE WHEN E.EmpId != ReportingManager THEN 1 ELSE 0 END AS IsSubordinate
FROM #Emp E;
I want the query to be written using the joins instead of using the tables in Case statement.
I tried the below query. Please suggest any correction in terms of performance keeping view the future data size.
SELECT E.EmpId
,E.EmpName
,CASE
WHEN E.EmpId = E.ReportingManager
THEN 1
ELSE 0
END AS IsManager
,CASE WHEN HasSubordinate>0 THEN 1 ELSE 0 END HasSubordinates
,CASE WHEN E.EmpId != ReportingManager THEN 1 ELSE 0 END AS IsSubordinate
FROM #Emp E
LEFT JOIN (SELECT COUNT(*)HasSubordinate,ReportingTo Reporting FROM #EmpRelation ER GROUP BY ReportingTo)X ON X.Reporting=E.EmpID
Appreciate your help.
Thanks

Related

In PostgreSQL, how can I optimize a query with which I obtain the differences between the current column and the immediately previous one?

I have this audit table
User
date
text
text 2
u1
2023-01-01
hi
yes
u1
2022-12-20
hi
no
u1
2022-12-01
hello
maybe
And I need as a result, something like this:
User
date
text
text 2
u1
2023-01-01
null
x
u1
2022-12-20
x
x
u1
2022-12-01
null
null
So I can know which column changed from the last time.
Something like this is working, but I think may be a way to optimize it? or at least generate a "more easy to look" query? (i need the information for almost 20 columns, not only 3)
SELECT
ta.audit_date,
ta.audit_user,
CASE
WHEN ta.audit_operation = 'I' THEN 'Insert'
WHEN ta.audit_operation = 'U' THEN 'Update'
END AS action,
CASE WHEN ta.column1 <> (SELECT column1
FROM audit_table ta1
WHERE ta1.id = 9207 AND ta1.audit_date < ta.audit_date
ORDER BY ta1.audit_date DESC
LIMIT 1)
THEN 'X' ELSE null END column1,
CASE WHEN ta.column2 <> (SELECT column2
FROM audit_table ta1
WHERE ta1.id = 9207 AND ta1.audit_date < ta.audit_date
ORDER BY ta1.audit_date DESC
LIMIT 1)
THEN 'X' ELSE null END column2,
CASE WHEN ta.column3 <> (SELECT column3
FROM audit_table ta1
WHERE ta1.id = 9207 AND ta1.audit_date < ta.audit_date
ORDER BY ta1.audit_date DESC
LIMIT 1)
THEN 'X' ELSE null END column3
FROM
audit_table ta
WHERE
ta.id = 9207
ORDER BY
audit_date DESC
Thank you!
I think you can just use the LAG() analytic function here. If I understand correctly:
SELECT *, CASE WHEN text != LAG(text) OVER (ORDER BY date) THEN 'x' END AS text_label,
CASE WHEN text2 != LAG(text) OVER (ORDER BY date) THEN 'x' END AS text2_label
FROM yourTable
ORDER BY date;

LEFT OUTER JOIN Increasing SUM. How to Prevent This?

Simplified version of query below, but fundamental gist of it:
WITH ClientSpend AS
(
SELECT
c.ClientName
, CONVERT(INT, (ROUND(SUM(CASE WHEN e.Type = 1 THEN e.Dollars ELSE 0 END), 0))) AS 1_Dollars
, CONVERT(INT, (ROUND(SUM(CASE WHEN e.Type = 2 THEN e.Dollars ELSE 0 END), 0))) AS 2_Dollars
-- There's a bunch more of these for different 'Types'
FROM Expense e WITH(NOLOCK)
INNER JOIN Client c WITH(NOLOCK)
ON c.ClientID = e.ClientID
GROUP BY c.ClientName
)
SELECT
ClientName
, 1_Dollars
, 2_Dollars
FROM ClientSpend
GROUP BY ClientName
Type 2 has its own Expense table which breaks out into more granular detail that I need for a final CASE/SUM line in the CTE SELECT.
I tried testing the above query with a LEFT JOIN to this [ExpenseType2] table ON as many indexes as I can, and I noticed that the SUM on the 2_Dollars is higher when doing this. I'm assuming it's making multiple records even though I'm not selecting anything from the [ExpenseType2] table.
How do I prevent this?
Thanks,
Why not using a sub query? Or a simple select statement? Or you may need to assert more information with sample data.
SELECT first_name, 1_Dollars, 2_Dollars FROM
(
SELECT
c.ClientName
, CONVERT(INT, (ROUND(SUM(CASE WHEN e.Type = 1 THEN e.Dollars ELSE 0 END), 0))) AS 1_Dollars
, CONVERT(INT, (ROUND(SUM(CASE WHEN e.Type = 2 THEN e.Dollars ELSE 0 END), 0))) AS 2_Dollars
-- There's a bunch more of these for different 'Types'
FROM Expense e WITH(NOLOCK)
INNER JOIN Client c WITH(NOLOCK)
ON c.ClientID = e.ClientID
GROUP BY c.ClientName
) a

CREATE, INSERT INTO & UPDATE vs CREATE & SELECT

I'm writing a big sql script in PostgreSQL (Netezza) and I would like to define the best strategy to create and update a [table] from another [ext_table]. As you can see, some fields (bi, i=1...n) are calculated from the source fields (ai, i=1...n) with conditions using CASE. Which is more efficient and why?
1) Create, insert and then update:
CREATE TABLE <table> (a1,a2,a3,...b1,b2,b3...);
INSERT INTO [table] (a1,a2,a3,...) SELECT a1,a2,a3,... FROM [ext_table];
UPDATE [table] SET
b1=CASE WHEN a1=1 THEN 'Y' ELSE 'N' END,
b2=CASE WHEN a2='A' THEN 1 ELSE 0 END,
b3=CASE WHEN a2='Y' THEN 1 ELSE 0 END;
2) Create and populate while selecting:
CREATE TABLE [table] AS (
SELECT a1,a2,a3,...,
(CASE WHEN a1=1 THEN 'Y' ELSE 'N' END) as b1,
(CASE WHEN a2='A' THEN 1 ELSE 0 END) as b2,
(CASE WHEN a2='Y' THEN 1 ELSE 0 END) as b3,
....
FROM [ext_table]
);

unexplained error in sql execution

UPDATE amc_machine b
SET with_parts = a.with_parts,
amc_validity_upto = a.amc_validity_upto
FROM (SELECT CASE
WHEN count(*) > 0 THEN (SELECT DISTINCT ON (machine_id) with_parts, amc_validity_upto, machine_id
FROM amc_amcdetail
WHERE machine_id = 2 AND id != 1
ORDER BY machine_id, amc_validity_upto DESC)
WHEN count(*) = 0 THEN (SELECT FALSE AS with_parts, NULL AS amc_validity_upto, 2 AS machine_id)
END AS a
FROM (SELECT DISTINCT ON (machine_id) with_parts, amc_validity_upto, machine_id
FROM amc_amcdetail
WHERE machine_id = 2
ORDER BY machine_id, amc_validity_upto
) AS T) AS foo
WHERE a.machine_id = b.id
The error shown is
ERROR: subquery must return only one column
LINE 5: WHEN count(*) > 0 THEN (SELECT DISTINCT ON (machine_id) w...
Can anyone tell what seems to be the problem.
Basically the query is to update on table b with data from table a if exists, else update with null , false as the case is.
The query executes when standalone. I am using Postgres 9.3, but deployment will be on postgres9.1
The subquery returns 3 columns
SELECT DISTINCT ON (machine_id) with_parts, amc_validity_upto, machine_id
Make it return only one
SELECT DISTINCT ON (machine_id) with_parts

SQL Server 2000: how do i get a list of tables and the row counts? [duplicate]

This question already has answers here:
Query to list number of records in each table in a database
(23 answers)
Closed 8 years ago.
I know that I can get a list of tables with
SELECT TABLE_NAME FROM information_schema.tables
WHERE NOT TABLE_NAME='sysdiagrams'
AND TABLE_SCHEMA = 'dbo'
AND TABLE_TYPE= 'BASE TABLE'
But I'm not sure how to modify that to get a 2nd column with the current count of rows for the tables. I though of something like this:
DECLARE #tbl VARCHAR(200)
(SELECT #tbl = TABLE_NAME, TABLE_NAME,
(SELECT COUNT(ID) AS Cnt FROM #tbl)
FROM information_schema.tables
WHERE NOT TABLE_NAME='sysdiagrams'
AND TABLE_SCHEMA = 'dbo'
AND TABLE_TYPE= 'BASE TABLE')
I know the above is not valid T-SQL but I think it gets the point of what I would like the have done. This is for SQL Server 2000. I would prefer not to use store procedures if at all possible.
A quick and dirty way (includes uncommitted changes and possibly forwarding pointers on heaps)
select o.name, rows
from sysindexes i join sysobjects o on o.id=i.id
where indid < 2 and type='U'
exec sp_MSforeachtable 'select count(*) as nr_of_rows, ''?'' as table_name from ?'
You can go whole hog on this one. The problem with using sysIndexes to get rowcounts is that they're not always up to date. There is a way to make them all up to date, though. The following code will give you row counts for each table and a whole bunch more.
/**********************************************************************************************************************
Purpose:
Returns a single result set similar to sp_Space used for all user tables at once.
Notes:
1. May be used as a view, stored procedure, or table-valued function.
2. Must comment out 1 "Schema" in the SELECT list below prior to use. See the adjacent comments for more info.
Revision History:
Rev 00 - 22 Jan 2007 - Jeff Moden
- Initital creation for SQL Server 2000
Rev 01 - 11 Mar 2007 - Jeff Moden
- Add automatic page size determination for future compliance
Rev 02 - 05 Jan 2008 - Jeff Moden
- Change "Owner" to "Schema" in output. Add optional code per Note 2 to find correct schema name
**********************************************************************************************************************/
--===== Ensure that all row counts, etc is up to snuff
-- Obviously, this will not work in a view or UDF and should be removed if in a view or UDF. External code should
-- execute the command below prior to retrieving from the view or UDF.
DBCC UPDATEUSAGE(0) WITH COUNT_ROWS, NO_INFOMSGS
--===== Return the single result set similar to what sp_SpaceUsed returns for a table, but more
SELECT DBName = DB_NAME(),
--SchemaName = SCHEMA_NAME(so.UID), --Comment out if for SQL Server 2000
SchemaName = USER_NAME(so.UID), --Comment out if for SQL Server 2005
TableName = so.Name,
TableID = so.ID,
MinRowSize = MIN(si.MinLen),
MaxRowSize = MAX(si.XMaxLen),
ReservedKB = SUM(CASE WHEN si.IndID IN (0,1,255) THEN si.Reserved ELSE 0 END) * pkb.PageKB,
DataKB = SUM(CASE WHEN si.IndID IN (0,1 ) THEN si.DPages ELSE 0 END) * pkb.PageKB
+ SUM(CASE WHEN si.IndID IN ( 255) THEN ISNULL(si.Used,0) ELSE 0 END) * pkb.PageKB,
IndexKB = SUM(CASE WHEN si.IndID IN (0,1,255) THEN si.Used ELSE 0 END) * pkb.PageKB
- SUM(CASE WHEN si.IndID IN (0,1 ) THEN si.DPages ELSE 0 END) * pkb.PageKB
- SUM(CASE WHEN si.IndID IN ( 255) THEN ISNULL(si.Used,0) ELSE 0 END) * pkb.PageKB,
UnusedKB = SUM(CASE WHEN si.IndID IN (0,1,255) THEN si.Reserved ELSE 0 END) * pkb.PageKB
- SUM(CASE WHEN si.IndID IN (0,1,255) THEN si.Used ELSE 0 END) * pkb.PageKB,
Rows = SUM(CASE WHEN si.IndID IN (0,1 ) THEN si.Rows ELSE 0 END),
RowModCtr = MIN(si.RowModCtr),
HasTextImage = MAX(CASE WHEN si.IndID IN ( 255) THEN 1 ELSE 0 END),
HasClustered = MAX(CASE WHEN si.IndID IN ( 1 ) THEN 1 ELSE 0 END)
FROM dbo.SysObjects so,
dbo.SysIndexes si,
(--Derived table finds page size in KB according to system type
SELECT Low/1024 AS PageKB --1024 is a binary Kilo-byte
FROM Master.dbo.spt_Values
WHERE Number = 1 --Identifies the primary row for the given type
AND Type = 'E' --Identifies row for system type
) pkb
WHERE si.ID = so.ID
AND si.IndID IN (0, --Table w/o Text or Image Data
1, --Table with clustered index
255) --Table w/ Text or Image Data
AND so.XType = 'U' --User Tables
AND PERMISSIONS(so.ID) <> 0
GROUP BY so.Name,
so.UID,
so.ID,
pkb.PageKB
ORDER BY ReservedKB DESC
how about "dtproperties" and "sysdiagrams" ?
these tables will show up as user table incorrectly