How to transform Access data similar to crosstab - sql

I have data that I want to display similar to a cross-tab query but not quite. The data I have looks like this with each segment of data on a different row:
I want the data to be consolidated to be all on one row for each client, like this:
I've attempted this with a cross-tab query but I'm not wanting to total any of the fields and there are several data point for each product (Type, Name, PurchaseDate, etc).
Any help is greatly appreciated!

Not a very practical presentation of data but it is possible. Need a unique identifier field - autonumber should serve - I called it RID. Consider:
Query 1:
SELECT RID, ID, FirstName, LastName, Dept, ProductType AS Data, "PT" AS Cat FROM Table1
UNION SELECT RID, ID, FirstName, LastName, Dept, ProductName, "PN" FROM Table1
UNION SELECT RID, ID, FirstName, LastName, Dept, PurchaseDate, "PD" FROM Table1
UNION SELECT RID, ID, FirstName, LastName, Dept, PurchaseCost, "PC" FROM Table1
UNION SELECT RID, ID, FirstName, LastName, Dept, DeliveryDate, "DD" FROM Table1;
Query 2:
TRANSFORM First(Query1.Data) AS FirstOfData
SELECT Query1.ID, Query1.FirstName, Query1.LastName, Query1.Dept
FROM Query1
GROUP BY Query1.ID, Query1.FirstName, Query1.LastName, Query1.Dept
PIVOT DCount("*","Query1","ID=" & [ID] & " AND Cat='" & [Cat] & "' AND RID<" & [RID])+1 & [Cat];
However, there is a limit of 255 fields so there may be more data than can be handled.

Related

SQL Select column which is not used in select section of subquery which find duplicates

I am trying to find in my database records which has duplicated fields like name, surname and type.
Example:
SELECT name, surname, type, COUNT(*)
FROM customers
GROUP BY name, surname
HAVING COUNT(*)>1
Query results:
Robb|Stark|1|2
Tyrion|Lannister|1|3
So we have duplicated customer with name and surname "Robb Stark" 2 times and "Tyrion Lannister" 3 times
Now, I want to know the id of these records.
I found similar problem described here:
Finding duplicate values in a SQL table
there is answer but no example.
Use COUNT as an analytic function:
WITH cte AS (
SELECT *, COUNT(*) OVER (PARTITION BY name, surname) cnt
FROM customers
)
SELECT * -- return all columns
FROM cte
WHERE cnt > 1
ORDER BY name, surname;
The simplest way will be to use the EXISTS as follows:
SELECT t.*
FROM customers t
where exists
(select 1 from customers tt
where tt.name = t.name
and tt.surname = t.surname
and tt.id <> t.id)
Or use your original query in IN clause as follows:
select * from customers where (name, surname) in
(SELECT name, surname
FROM customers
GROUP BY name, surname
HAVING COUNT(*)>1)
If you want one row per group of duplicate, with the list of id in a comma separated string, you can just use string aggration with your existing query:
SELECT name, surname, COUNT(*) as cnt,
STRING_AGG(id, ',') WITHIN GROUP (ORDER BY id) as all_ids
FROM customers
GROUP BY name, surname
HAVING COUNT(*) > 1

SQL Union Select for alternate data

I created an sql query with union select and here is the query to join the two columns into one.
(select top 10 FirstName from Users) union (select top 10 LastName from Users)
Here is the Result:
QUERY RESULT 1
And here is the original data for the result 1 of union select.
ORIGINAL DATA
So, here is my problem.
How do I select the data of each firstname and lastname with the same column but the first one is firstname and the second one is lastname. For example:
Tumbaga Temp - <FirstName>
Villamor - <LastName>
Jun - <FirstName>
Villamor - <LastName>
FN83 - <FirstName>
Lising Geron - <LastName>
So on and so fort.
I am new in sql query. Thanks for your help.
We add a common row_number() to both parts to essentially group them, then order by this and the name type to display in clusters of first/last pairs
select 'First' as thename,
Firstname,
row_number() over(order by firstname) rn
from Users
union all
select 'Last',
Lastname,
row_number() over(order by firstname)
from users
order by rn, thename
If you only want the 1st 10, then wrap this and add a clause
select *
from
(
select 'First' as thename,
Firstname,
row_number() over(order by firstname) rn
from Users
union all
select 'Last',
Lastname,
row_number() over(order by firstname)
from users
)
where rn <=10
order by rn, thename
No need to use union, As per your description You have two columns 'firstName' and 'lastName' in a table and you want both in a single column. Just try the following query-:
select FirstName+' '+LastName as FullName from Users
SQL Server
you can add a column to both queries with your favourite data to be selected.
(select top 10 FirstName, 'FirstName' as NameType from SysUser) union (select top 10 LastName, 'LastName' as NameType from SysUser)

Deleting duplicates in a table based on a criteria only in SQL

Let's say I have a table with columns:
CustomerNumber
Lastname
Firstname
PurchaseDate
...and other columns that do not change anything in the question if they're not shown here.
In this table I could have many rows for the same customer with different purchase dates (I know, poorly designed... I'm only trying to fix an issue for reporting, not really trying to fix the root of the problem).
How, in SQL, can I keep one record per customer with the latest date, and delete the rest? A group by doesn't seem to be working for my case
;with a as
(
select row_number() over (partition by CustomerNumber, Lastname, Firstname order by PurchaseDate desc) rn
from <table>
)
delete from a where rn > 1
This worked for me (on DB2):
DELETE FROM my_table
WHERE (CustomerNumber, Lastname, Firstname, PurchaseDate)
NOT IN (
SELECT CustomerNumber, Lastname, Firstname, MAX(PurchaseDate)
FROM my_table
GROUP BY CustomerNumber, Lastname, FirstName
)
SELECT CustomerNumber, Lastname, Firstname, MAX(PurchaseDate) LatestPurchaseDate
FROM Table
GROUP BY CustomerNumber, Lastname, Firstname
The MAX will select the highest (latest) date and show that date for each unique combination of the GROUP BY columns.
EDIT: I misunderstood that you wanted to delete records for all but the latest purchase date.
WITH Keep AS
(
SELECT CustomerNumber, Lastname, Firstname, MAX(PurchaseDate) LatestPurchaseDate
FROM Table
GROUP BY CustomerNumber, Lastname, Firstname
)
DELETE FROM Table
WHERE NOT EXISTS
(
SELECT *
FROM Keep
WHERE Table.CustomerNumber = Keep.CustomerNumber
AND Table.Lastname = Keep.Lastname
AND Table.Firstname = Keep.Firstname
AND Table.PurchaseDate = Keep.LastPurchaseDate
)

SQl server query multiple aggregate columns

I need to write a query in sql server to data get like this.
Essentially it is group by dept, race, gender and then
SUM(employees_of_race_by_gender),Sum(employees_Of_Dept).
I could get data of first four columns, getting sum of employees in that dept is becoming difficult.
Could you pls help me in writing the query?
All these details in same table Emp. Columns of Emp are Emp_Number, Race_Name,Gender,Dept
Your "num_of_emp_in_race" is actually by Gender too
SELECT DISTINCT
Dept,
Race_name,
Gender,
COUNT(*) OVER (PARTITION BY Dept, Race_name, Gender) AS num_of_emp_in_race,
COUNT(*) OVER (PARTITION BY Dept) AS num_of_emp_dept
FROM
MyTable
You should probably have this
COUNT(*) OVER (PARTITION BY Dept, Gender) AS PerDeptRace
COUNT(*) OVER (PARTITION BY Dept, Race_name) AS PerDeptGender,
COUNT(*) OVER (PARTITION BY Dept, Race_name, Gender) AS PerDeptRaceGender,
COUNT(*) OVER (PARTITION BY Dept) AS PerDept
Edit: the DISTINCT appears to be applied before the COUNT (which would odd based on this) so try this instead
SELECT DISTINCT
*
FROM
(
SELECT
Dept,
Race_name,
Gender,
COUNT(*) OVER (PARTITION BY Dept, Race_name, Gender) AS num_of_emp_in_race,
COUNT(*) OVER (PARTITION BY Dept) AS num_of_emp_dept
FROM
MyTable
) foo
Since the two sums you're looking for are based on a different aggregation, you need to calculate them separately and join the result. In such cases I first build the selects to show me the different results, making it easy to catch errors early:
SELECT Dept, Gender, race_name, COUNT(*) as num_of_emp_in_race
FROM Emp
GROUP BY 1, 2, 3
SELECT Dept, COUNT(*) as num_of_emp_in_dept
FROM Emp
GROUP BY 1
Afterwards, joining those two is pretty straight forward:
SELECT *
FROM ( first statement here ) as by_race
JOIN ( second statement here ) as by_dept ON (by_race.Dept = by_dept.Dept)

How we can use CTE in subquery in sql server?

How we can use a CTE in a subquery in SQL Server?
like:
SELECT id (I want to use CTE here), name FROM table_name
Just define your CTE on top and access it in the subquery?
WITH YourCTE(blubb) AS
(
SELECT 'Blubb'
)
SELECT id,
(SELECT blubb FROM YourCTE),
name
FROM table_name
It doesn't work:
select id (I want to use CTE here), name from table_name
It's not possible to use CTE in sub queries.
You can realize it as a work around:
CREATE VIEW MyCTEView AS ..here comes your CTE-Statement.
Then you are able to do this:
select id (select id from MyCTEView), name from table_name
Create a view with CTE/ Multiple CTEs with UNION sets of all CTEs
CREATE VIEW [dbo].[_vEmployees]
AS
WITH
TEST_CTE(EmployeeID, FirstName, LastName, City, Country)
AS (
SELECT EmployeeID, FirstName, LastName, City, Country FROM Employees WHERE EmployeeID = 4
),
TEST_CTE2
AS (
SELECT EmployeeID, FirstName, LastName, City, Country FROM Employees WHERE EmployeeID = 7
)
SELECT EmployeeID, FirstName, LastName, City, Country FROM TEST_CTE UNION SELECT * FROM TEST_CTE2
GO
Now, use it into sub query
SELECT * FROM Employees WHERE EmployeeID IN (SELECT EmployeeID FROM _vEmployees)