Related
I have two tables:
Company Table
Id,
CompanyName
Sale Table:
Id,
CompanyId,
Date,
Value
I need to group sales by date and by company and display it like this:
CompanyId CompanyName Date Value
--------- -------------------- ---------- --------
1 Company 1 2021-10-01 2832.98
2 Company 2 2021-10-01 8112.81
1 Company 1 2021-10-02 2182.12
2 Company 2 2021-10-02 3521.11
I know I can easily achieve it with this
SELECT s.CompanyId, c.CompanyName, s.Date, SUM(s.Value) FROM Sale s
JOIN Company c on s.CompanyId = c.Id
GROUP BY s.Date, s.CompanyId, c.CompanyName
The problem is that when I include CompanyName in the GROUP BY clause, it gets an order of magnitude slower. I may be able to circunvent it by adding a new index, but that's not an option right now.
I was able to make it run faster using this query
SELECT
s.CompanyId,
(SELECT CompanyName FROM Company WHERE Id = s.CompanyId) as CompanyName
s.Date,
SUM(s.Value)
FROM Sale s
GROUP BY s.Date, s.CompanyId
But I want to know if there's a faster/better method. The group by without the CompanyName runs in 2 seconds, If I add CompanyName to the GROUP BY it adds 20 seconds to the query. Using the last query I listed, it runs in around 5 seconds.
defer the lookup of name until after the grouping?
Not tested...
select i.CompanyId,c.CompanyName,i.Date,i.Value
From Company c join(
SELECT
s.CompanyId,
s.Date,
SUM(s.Value) as [Value]
FROM Sale s
GROUP BY s.Date, s.CompanyId) i
on i.CompanyId = c.CompanyId
I could not explain the problem clearly in the header but here is the issue.
I am using SQL Server.
I have a table that has Universities and Subjects.
University Subject
Melbourne Math
Melbourne Physics
Melbourne English
Ottawa Physics
Ottawa English
Ottawa Arts
Ottawa Computer
Sydney Math
Sydney Medicine
Sydney English
Sydney Computer
.
.
.
I want to do some calculations in one select statement
Here is my SQL
SELECT Subject, Count(*) SubjectsCount
FROM Table
GROUP BY Subject
Gives
Subject SubjectsCount
Math 39
Physics 23
English 47
Medicine 13
I want to fnd number of distinct Universities in the same query
Subject SubjectsCount UniversitiesNo
Math 39 52
Physics 23 52
English 47 52
Medicine 13 52
I tried this
SELECT Subject, Count(*) SubjectsCount, Count(*) OVER() AS UniversitiesNo
FROM Table
GROUP BY Subject
but this gave all records count
How can I specify for Universities distinct only?
You can CROSS JOIN a query that returns the number of all distinct universities:
SELECT t.Subject,
COUNT(*) SubjectsCount,
u.UniversitiesNo
FROM tablename t
CROSS JOIN (SELECT COUNT(DISTINCT University) UniversitiesNo FROM tablename) u
GROUP BY t.Subject, u.UniversitiesNo
Or even simpler:
SELECT Subject,
COUNT(*) SubjectsCount,
(SELECT COUNT(DISTINCT University) FROM tablename) UniversitiesNo
FROM tablename
GROUP BY Subject
See the demo.
Use COUNT DISTINCT:
SELECT Subject
, Count(*) SubjectsCount
, Count(DISTINCT University) AS UniversitiesNo
FROM Table
GROUP BY Subject
This query gives the number of distinct universites per Subject.
To get distinct number of universities simply CROSS JOIN:
SELECT t1.Subject,
t1.SubjectsCount,
t2.cnt
FROM (
SELECT Subject, Count(*) SubjectsCount
FROM Table1
GROUP BY Subject
) AS t1
CROSS JOIN (SELECT COUNT(DISTINCT University) FROM Table1) AS t2(cnt)
Demo here
I am using SQL Server 2008.
This is my query output :
Reg_Id | ITSkillName
----------------------
118 | JAVASCRIPT
371 | PHP
371 | ANDROID
6170 | PHP
Here, Reg_Id is foreign key. I want Reg_Id which have PHP and ANDROID skills.
So I have tried like
SELECT *
FROM dbo.ITSkill AS is2
WHERE ITSkillName = 'PHP' AND ITSkillName = 'ANDROID'
but it returns 0 records. Please help me. Thank you.
This is a relational division problem. If the Reg_ID and ITSkillName columns, taken together, are unique in this table, then we can just do:
SELECT Reg_ID,COUNT(*) FROM dbo.ITSkill AS is2
WHERE ITSkillName IN('PHP','ANDROID')
GROUP BY Reg_ID
HAVING COUNT(*) = 2
This generally extends to more skills by adjusting the IN clause and the expected count.
I.e. if you have a table-valued parameter containing the skills to search for, you could have:
SELECT Reg_ID,COUNT(*) FROM dbo.ITSkill AS is2
WHERE ITSkillName IN(select Skill from #SearchSkills)
GROUP BY Reg_ID
HAVING COUNT(*) = (select COUNT(*) from #SearchSkills)
Where #SearchSkills is the table-valued parameter.
You need to JOIN the table to itself to get the results you want.
SELECT A.Reg_Id
FROM dbo.ITSkill A
INNER JOIN dbo.ITSkill B ON A.Reg_Id = B.Reg_Id AND B.ITSkillName='PHP'
WHERE A.ITSkillName='ANDROID'
If you need to match an arbitrary number of skills, but can't guarantee that Reg_ID, ITSkillName is unique, you can use a CTE to slightly modify Damien_The_Unbeliever's answer as follows:
;WITH UniqueSkills AS (SELECT DISTINCT Reg_ID, ITSkillName FROM dbo.ITSkill)
SELECT Reg_ID,COUNT(*) FROM UniqueSkills AS is2
WHERE ITSkillName IN(select Skill from #SearchSkills)
GROUP BY Reg_ID
HAVING COUNT(*) = (select COUNT(*) from #SearchSkills)
Think in sets! What you're looking for is the intersection of two sets: those with PHP skills, and those with ANDROID skills. SQL has an INTERSECT operator:
SELECT Reg_ID FROM dbo.ITSkill
WHERE Skill = 'PHP'
INTERSECT
SELECT Reg_ID FROM dbo.ITSkill
WHERE Skill = 'ANDROID'
SELECT * FROM dbo.ITSkill AS is2
WHERE ITSkillName = 'PHP'
AND Reg_Id IN( SELECT DISTINCT Reg_Id
FROM dbo.ITSkill
WHERE ITSkillName = 'ANDROID')
Test
DECLARE #t TABLE (Reg_Id INT,ITSkillName VARCHAR(20))
INSERT INTO #t
VALUES
(118,'JAVASCRIPT'),
(371,'PHP'),
(371,'ANDROID'),
(6170,'PHP')
SELECT * FROM #t AS is2
WHERE ITSkillName = 'PHP'
AND Reg_Id IN( SELECT DISTINCT Reg_Id
FROM #t
WHERE ITSkillName = 'ANDROID')
Result Set
Reg_Id ITSkillName
371 PHP
As marc_s suggested, INTERSECT is a valid alternative. However, depending on how many various Skills there are, it can get kind of heavy since the query optimizer (in my experience at least) may choose less optimal ways to execute the query.
One other option at least, would be to use this:
SELECT s.*
FROM dbo.ITSkill s
JOIN
(SELECT Reg_ID
FROM dbo.ITSkill AS is2
WHERE ITSkillName IN ('PHP','ANDROID')
GROUP BY Reg_ID
HAVING COUNT(DISTINCT ITSkillName) = 2) SRC
ON SRC.Reg_ID = s.Reg_ID
Now obviously, you need to update the HAVING COUNT value to match the number of parameters in the IN clause. In code you may sometimes concatenate hundreds of INTERSECT queries, and that's where this model really starts to shine. At minimum it should be around equally effective performance-wise.
EDIT: Bah, just noticed damien had the same idea there! But this also has the join to get the results as per the OP so I'll leave it here. Give the creds and fortune to damien. ;)
Let's say I have the following example table
GroupID ItemID Created
-----------------------------------------------
A ABC 5/1/2009 13:02
A XZY 5/1/2009 13:01
A LMO 5/1/2009 13:03
A DEF 5/1/2009 13:00
A PQR 5/1/2009 13:04
B WXY 5/1/2009 13:02
B HIJ 5/1/2009 13:03
B STU 5/1/2009 13:01
How can I return the first ItemID for each group based on the Created column? I need a query to return the following:
GroupID ItemID Created
-----------------------------------------------
A DEF 5/1/2009 13:00
B STU 5/1/2009 13:01
The data set I'm working with may have several thousand to a few million rows, so I'd like to avoid any costly subqueries if possible. I was thinking maybe I could do it with an inner join, but my initial attempts led to my own confusion.
Edit: So far, I have the following:
select t2.ItemID, count(*) from
(select GroupID, min(created) as created from table) t1
inner join table t2 on t1.created = t2.created
group by t2.itemid
Any reason this isn't going to work? It's slower than I'd like, but it's updating a summary table, so it's not a huge issue.
SELECT myTable.*
FROM myTable
INNER JOIN (
SELECT GroupID, Min(Created) AS MinCreated
FROM myTable) AS SummarizedTable
ON myTable.GroupID = SummarizedTable.GroupID
WHERE myTable.Created = SummarizedTable.MinCreated
Note: Done without help of query analyzer. So, please be kind :)
No inner joins needed. Classic PARTITION BY problem.
Not tested but this should put you on the right track.
SELECT RowNumber() OVER(PARTITION BY GroupID ORDER BY Created ASC) AS RowNum, *
FROM YourTable
Depends on the SQL Server version but 2005 onwards have the ranking functions which can simplify it
Select GroupID, ItemID, Created
FROM
(
select GroupID, ItemID, Created, DENSE_RANK ( ) OVER ( partition by GroupID
order by Created asc) as Rank
from yourTable
) as A
where Rank = 1
One note though, is that if 2 record tie, it would return both, this might be advantageous, or a pain depending on what you needed, it can be dropped to one using select distinct.
select m1.Groupid, m1.itemid, m1.created
from mytable m1
join
(select groupid,min(created) as created from mytable) m2
on m1.groupid = m2.group_id and m1.created = m2.created
I want to learn how to combine two db tables which have no fields in common. I've checked UNION but MSDN says :
The following are basic rules for combining the result sets of two queries by using UNION:
The number and the order of the columns must be the same in all queries.
The data types must be compatible.
But I have no fields in common at all. All I want is to combine them in one table like a view.
So what should I do?
There are a number of ways to do this, depending on what you really want. With no common columns, you need to decide whether you want to introduce a common column or get the product.
Let's say you have the two tables:
parts: custs:
+----+----------+ +-----+------+
| id | desc | | id | name |
+----+----------+ +-----+------+
| 1 | Sprocket | | 100 | Bob |
| 2 | Flange | | 101 | Paul |
+----+----------+ +-----+------+
Forget the actual columns since you'd most likely have a customer/order/part relationship in this case; I've just used those columns to illustrate the ways to do it.
A cartesian product will match every row in the first table with every row in the second:
> select * from parts, custs;
id desc id name
-- ---- --- ----
1 Sprocket 101 Bob
1 Sprocket 102 Paul
2 Flange 101 Bob
2 Flange 102 Paul
That's probably not what you want since 1000 parts and 100 customers would result in 100,000 rows with lots of duplicated information.
Alternatively, you can use a union to just output the data, though not side-by-side (you'll need to make sure column types are compatible between the two selects, either by making the table columns compatible or coercing them in the select):
> select id as pid, desc, null as cid, null as name from parts
union
select null as pid, null as desc, id as cid, name from custs;
pid desc cid name
--- ---- --- ----
101 Bob
102 Paul
1 Sprocket
2 Flange
In some databases, you can use a rowid/rownum column or pseudo-column to match records side-by-side, such as:
id desc id name
-- ---- --- ----
1 Sprocket 101 Bob
2 Flange 101 Bob
The code would be something like:
select a.id, a.desc, b.id, b.name
from parts a, custs b
where a.rownum = b.rownum;
It's still like a cartesian product but the where clause limits how the rows are combined to form the results (so not a cartesian product at all, really).
I haven't tested that SQL for this since it's one of the limitations of my DBMS of choice, and rightly so, I don't believe it's ever needed in a properly thought-out schema. Since SQL doesn't guarantee the order in which it produces data, the matching can change every time you do the query unless you have a specific relationship or order by clause.
I think the ideal thing to do would be to add a column to both tables specifying what the relationship is. If there's no real relationship, then you probably have no business in trying to put them side-by-side with SQL.
If you just want them displayed side-by-side in a report or on a web page (two examples), the right tool to do that is whatever generates your report or web page, coupled with two independent SQL queries to get the two unrelated tables. For example, a two-column grid in BIRT (or Crystal or Jasper) each with a separate data table, or a HTML two column table (or CSS) each with a separate data table.
This is a very strange request, and almost certainly something you'd never want to do in a real-world application, but from a purely academic standpoint it's an interesting challenge. With SQL Server 2005 you could use common table expressions and the row_number() functions and join on that:
with OrderedFoos as (
select row_number() over (order by FooName) RowNum, *
from Foos (nolock)
),
OrderedBars as (
select row_number() over (order by BarName) RowNum, *
from Bars (nolock)
)
select *
from OrderedFoos f
full outer join OrderedBars u on u.RowNum = f.RowNum
This works, but it's supremely silly and I offer it only as a "community wiki" answer because I really wouldn't recommend it.
SELECT *
FROM table1, table2
This will join every row in table1 with table2 (the Cartesian product) returning all columns.
select
status_id,
status,
null as path,
null as Description
from
zmw_t_status
union
select
null,
null,
path as cid,
Description from zmw_t_path;
try:
select * from table 1 left join table2 as t on 1 = 1;
This will bring all the columns from both the table.
If the tables have no common fields then there is no way to combine the data in any meaningful view. You would more likely end up with a view that contains duplicated data from both tables.
To get a meaningful/useful view of the two tables, you normally need to determine an identifying field from each table that can then be used in the ON clause in a JOIN.
THen in your view:
SELECT T1.*, T2.* FROM T1 JOIN T2 ON T1.IDFIELD1 = T2.IDFIELD2
You mention no fields are "common", but although the identifying fields may not have the same name or even be the same data type, you could use the convert / cast functions to join them in some way.
why don't you use simple approach
SELECT distinct *
FROM
SUPPLIER full join
CUSTOMER on (
CUSTOMER.OID = SUPPLIER.OID
)
It gives you all columns from both tables and returns all records from customer and supplier if Customer has 3 records and supplier has 2 then supplier'll show NULL in all columns
Select
DISTINCT t1.col,t2col
From table1 t1, table2 t2
OR
Select
DISTINCT t1.col,t2col
From table1 t1
cross JOIN table2 t2
if its hug data , its take long time ..
SELECT t1.col table1col, t2.col table2col
FROM table1 t1
JOIN table2 t2 on t1.table1Id = x and t2.table2Id = y
Joining Non-Related Tables
Demo SQL Script
IF OBJECT_ID('Tempdb..#T1') IS NOT NULL DROP TABLE #T1;
CREATE TABLE #T1 (T1_Name VARCHAR(75));
INSERT INTO #T1 (T1_Name) VALUES ('Animal'),('Bat'),('Cat'),('Duet');
SELECT * FROM #T1;
IF OBJECT_ID('Tempdb..#T2') IS NOT NULL DROP TABLE #T2;
CREATE TABLE #T2 (T2_Class VARCHAR(10));
INSERT INTO #T2 (T2_Class) VALUES ('Z'),('T'),('H');
SELECT * FROM #T2;
To Join Non-Related Tables , we are going to introduce one common joining column of Serial Numbers like below.
SQL Script
SELECT T1.T1_Name,ISNULL(T2.T2_Class,'') AS T2_Class FROM
( SELECT T1_Name,ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS S_NO FROM #T1) T1
LEFT JOIN
( SELECT T2_Class,ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS S_NO FROM #T2) T2
ON t1.S_NO=T2.S_NO;
select * from this_table;
select distinct person from this_table
union select address as location from that_table
drop wrong_table from this_database;
Very hard when you have to do this with three select statments
I tried all proposed techniques up there but it's in-vain
Please see below script. please advice if you have alternative solution
select distinct x.best_Achiver_ever,y.Today_best_Achiver ,z.Most_Violator from
(SELECT Top(4) ROW_NUMBER() over (order by tl.username) AS conj, tl.
[username] + '-->' + str(count(*)) as best_Achiver_ever
FROM[TiketFollowup].[dbo].N_FCR_Tikect_Log_Archive tl
group by tl.username
order by count(*) desc) x
left outer join
(SELECT
Top(4) ROW_NUMBER() over (order by tl.username) as conj, tl.[username] + '-->' + str(count(*)) as Today_best_Achiver
FROM[TiketFollowup].[dbo].[N_FCR_Tikect_Log] tl
where convert(date, tl.stamp, 121) = convert(date,GETDATE(),121)
group by tl.username
order by count(*) desc) y
on x.conj=y.conj
left outer join
(
select ROW_NUMBER() over (order by count(*)) as conj,username+ '--> ' + str( count(dbo.IsViolated(stamp))) as Most_Violator from N_FCR_Ticket
where dbo.IsViolated(stamp) = 'violated' and convert(date,stamp, 121) < convert(date,GETDATE(),121)
group by username
order by count(*) desc) z
on x.conj = z.conj
Please try this query:
Combine two tables that have no common columns:
SELECT *
FROM table1
UNION
SELECT *
FROM table2
ORDER BY orderby ASC