I'm banging my head with some SQL query and pretty much the logic behind it.
Let's assume we have these tables:
Table hotels
+----+---------+
| id | name |
+----+---------+
| 1 | Hotel A |
+----+---------+
Table hotel_rooms
+----+----------+-----------+
| id | hotel_id | room_type |
+----+----------+-----------+
| 1 | 1 | dbl | <- can be used as A,B,C,D,E,F
| 2 | 1 | dbl | <- can be used as B,C,D,E,F
| 3 | 1 | sng | <- can be used as A
| 4 | 1 | trp | <- can be used as D,E,F
+----+----------+-----------+
Table hotel_room_usages
+----+---------+-------+
| id | room_id | usage |
+----+---------+-------+
| 1 | 1 | B |
| 2 | 1 | C |
| 3 | 1 | A |
| 4 | 1 | D |
| 5 | 1 | E |
| 6 | 1 | F |
| 7 | 2 | B |
| 8 | 2 | C |
| 9 | 2 | D |
| 10 | 2 | E |
| 11 | 2 | F |
| 12 | 3 | A |
| 13 | 4 | D |
| 14 | 4 | E |
| 15 | 4 | F |
+----+---------+-------+
If I search for 2 rooms with usage A or 3 rooms with usage D as separate queries the result should be Hotel A with the corresponding IDs of the rooms.
The problem is if I search for 2 rooms with usage A and 3 rooms with usage D at the same time it returns also the hotel A because it doesn't count that some rooms can be used as A and D.
The rooms should be unique /total of 5/. The current example should not return a result because there are total of 4 rooms in the hotel.
does this help?
-- two rooms with usage a
select id from hotel_room_usages where usage = 'a'
-- three rooms with usage d
select id from hotel_room_usages where usage = 'd'
-- count of rooms with either
select count(distinct(room_id)) from hotel_room_usages where usage in ('a','d')
SELECT h.name AS hotel_name
, q.*
FROM
(
SELECT r.hotel_id
, COUNT(DISTINCT CASE WHEN ruA.room_id IS NOT NULL AND ruD.room_id IS NULL THEN ruA.room_id END) AS TotalRoomsOnlyA
, COUNT(DISTINCT CASE WHEN ruD.room_id IS NOT NULL AND ruA.room_id IS NULL THEN ruD.room_id END) AS TotalRoomsOnlyD
, COUNT(DISTINCT CASE WHEN ruA.room_id IS NOT NULL AND ruD.room_id IS NOT NULL THEN r.id END) AS TotalRoomsAandD
, COUNT(DISTINCT r.id) AS TotalRoomsAorD
FROM hotel_rooms AS r
LEFT JOIN hotel_room_usages AS ruA ON (ruA.room_id = r.id AND ruA.usage = 'A')
LEFT JOIN hotel_room_usages AS ruD ON (ruD.room_id = r.id AND ruD.usage = 'D')
WHERE (ruA.room_id IS NOT NULL OR ruD.room_id IS NOT NULL)
GROUP BY r.hotel_id
) q
JOIN hotels AS h ON (h.id = q.hotel_id)
CROSS JOIN (SELECT 2 AS a, 3 AS d) AS n
WHERE TotalRoomsAorD >= (a+d)
AND (
((TotalRoomsOnlyA + TotalRoomsAandD) >= a AND TotalRoomsOnlyD >= d) OR
(TotalRoomsOnlyA >= d AND (TotalRoomsOnlyD + TotalRoomsAandD) >= d) OR
((TotalRoomsOnlyA + TotalRoomsAandD/2) >= a AND (TotalRoomsOnlyD + TotalRoomsAandD/2) >= d)
)
ORDER BY h.name;
Test on db<>fiddle here
Related
I am looking to get all values from first table along with joinned values from second table.
Table 1 is fee_category with fields:
id | Category
1 | A
2 | B
3 | C
4 | D
Table 2 is fee_charge with fields:
id | std_id | particularID | CategoryID | assign | amount
1 | 1 | 1 | 1 | 0 | 1000
2 | 1 | 1 | 2 | 1 | 12000
3 | 1 | 2 | 3 | 0 | 3000
4 | 1 | 2 | 4 | 0 | 10
5 | 2 | 1 | 2 | 0 | 100
6 | 2 | 2 | 3 | 0 | 120
Base table is "fee_category" from which I need all values left joining with "fee_charge" from where I need values or NULL for a particular std_id and particularID
SELECT fee_category.id, fee_category.Category, fee_charge.std_id
, fee_charge.particularID, fee_charge.CategoryID, fee_charge.assign, fee_charge.amount FROM fee_category
LEFT join fee_charge on fee_category.id=fee_charge.CategoryID
where (fee_charge.std_id = 1 OR fee_charge.std_id IS NULL)
AND (fee_charge.particularID = 1 OR fee_charge.particularID IS NULL)
group By fee_category.id
order By fee_charge.assign DESC
Here I am trying to get all categories of std_id=1 and particularID=1
Correct result should be
id | Category | std_id | particularID | CategoryID | assign | amount
1 | A | 1 | 1 | 1 | 0 | 1000
1 | B | 1 | 1 | 2 | 1 | 12000
1 | C | 1 | NULL | NULL | NULL | NULL
1 | D | 1 | NULL | NULL | NULL | NULL
I am trying various versions of the above query but not getting proper result. Please help
SELECT fee_category.id
, fee_category.Category
, X.std_id
, X.particularID
, X.CategoryID
, X.assign
, X.amount
FROM fee_category
LEFT JOIN
(SELECT * FROM fee_charge
WHERE fee_charge.std_id = 1
AND fee_charge.particularID = 1) AS X
ON x.CategoryID = fee_category.id
It's very hard to follow when the fiddle doesn't match the question, so I may have misunderstood, but perhaps you're after something like this...
SELECT x.id
, z.category
, x.std_id
, y.particularID
, y.categoryID
, y.assign
, y.amount
FROM fee_charge x
LEFT
JOIN fee_charge y
ON y.id = x.id
AND y.particularID = 1
JOIN fee_category z
ON z.id = x.categoryID
WHERE x.std_id = 1;
I have table it store hierarchy data in MySQL this table store stable relation but if each user less than 1000 buy removed and user User a lower level replace this is my code and work fine, after GROUP BY it contain all ancestor of descendant with compare then COUNT(*) AS level count level each user. This I have SQL code to compress data According to minimum buy for each user
+-------------+---------------+-------------+
| ancestor_id | descendant_id | path_length |
+-------------+---------------+-------------+
| 1 | 1 | 0 |
| 1 | 2 | 1 |
| 1 | 3 | 1 |
| 1 | 4 | 2 |
| 1 | 5 | 3 |
| 1 | 6 | 4 |
| 2 | 2 | 0 |
| 2 | 4 | 1 |
| 2 | 5 | 2 |
| 2 | 6 | 3 |
| 3 | 3 | 0 |
| 4 | 4 | 0 |
| 4 | 5 | 1 |
| 4 | 6 | 2 |
| 5 | 5 | 0 |
| 5 | 6 | 1 |
| 6 | 6 | 0 |
+-------------+---------------+-------------+
This is table buy
+--------+--------+
| userid | amount |
+--------+--------+
| 2 | 2000 |
| 4 | 6000 |
| 6 | 7000 |
| 1 | 7000 |
SQL code
SELECT a.*
FROM
( SELECT userid
FROM webineh_user_buys
GROUP BY userid
HAVING SUM(amount) >= 1000
) AS buys_d
JOIN
webineh_prefix_nodes_paths AS a
ON a.descendant_id = buys_d.userid
JOIN
(
SELECT userid
FROM webineh_user_buys
GROUP BY userid
HAVING SUM(amount) >= 1000
) AS buys_a on (a.ancestor_id = buys_a.userid )
JOIN
( SELECT descendant_id
, MAX(path_length) path_length
FROM webineh_prefix_nodes_paths
where a.ancestor_id = ancestor_id
GROUP
BY descendant_id
) b
ON b.descendant_id = a.descendant_id
AND b.path_length = a.path_length
GROUP BY a.descendant_id, a.ancestor_id
I need get max path_length where ancestor_id have At least 1000 amount buy but have error in where in subquery where a.ancestor_id = ancestor_id error code
1054 - Unknown column 'a.ancestor_id' in 'where clause'
I add SQLFidle demo.
You could use this query:
select m.userid as descendant,
p.ancestor_id,
p.path_length
from (
select b1.userid,
min(case when b2.amount >= 1000
then p.path_length
end) as path_length
from (select userid, sum(amount) amount
from webineh_user_buys
group by userid
having sum(amount) >= 1000
) as b1
left join webineh_prefix_nodes_paths p
on p.descendant_id = b1.userid
and p.path_length > 0
left join (select userid, sum(amount) amount
from webineh_user_buys
group by userid) as b2
on p.ancestor_id = b2.userid
group by b1.userid
) as m
left join webineh_prefix_nodes_paths p
on p.descendant_id = m.userid
and p.path_length = m.path_length
order by m.userid
Output for sample data in the question:
| userid | ancestor_id | path_length |
|--------|-------------|-------------|
| 1 | (null) | (null) |
| 2 | 1 | 1 |
| 4 | 2 | 1 |
| 6 | 4 | 2 |
SQL fiddle
This must be quite easy, but I cannot find a good solution myself.
I have two tables:
file
+----+--------+
| id | system |
+----+--------+
| 1 | AA |
| 2 | AA |
| 3 | BB |
| 4 | AA |
+----+--------+
feature
+----+---------+------+
| id | file_id | name |
+----+---------+------+
| 1 | 1 | A |
| 1 | 2 | A |
| 1 | 2 | B |
| 1 | 3 | B |
| 1 | 3 | C |
| 1 | 4 | A |
| 1 | 4 | B |
| 1 | 4 | C |
+----+---------+------+
and I want to count how many times a feature was added to files with a specific system. For that, I have the following query:
SELECT f.name, COUNT(*) AS nr
FROM dossier d
JOIN feature f
ON f.file_id = d.id
WHERE d.system = 'AA'
AND d.id NOT IN (3157,3168,3192)
GROUP BY f.name
which gives the desired output:
+------+----+
| name | nr |
+------+----+
| A | 3 |
| B | 2 |
| C | 1 |
+------+----+
Now I also want to know the total amount of files with the same specific system. A simple separate query would be:
SELECT COUNT(*) FROM file WHERE system = 'AA' AND id NOT IN (3157,3168,3192)
I've added the extra AND id NOT IN (which is irrelevant for this example) just to show that the actual query is much more complex. If I use a separate query to get the total I would have to duplicate that complexity, so I want to avoid that by returning the total from the same query.
So how can I count the number of files in the first query?
Desired output:
+------+----+-------+
| name | nr | total |
+------+----+-------+
| A | 3 | 3 |
| B | 2 | 3 |
| C | 1 | 3 |
+------+----+-------+
Here is one way using Sub-query
SELECT f.NAME,
Count(*) AS nr,
(SELECT Count(*)
FROM FILE
WHERE system = 'AA'
AND id NOT IN ( 3157, 3168, 3192 )) as Total
FROM dossier d
JOIN feature f
ON f.file_id = d.id
WHERE d.system = 'AA'
AND d.id NOT IN ( 3157, 3168, 3192 )
GROUP BY f.NAME
Or Use CROSS JOIN
SELECT *
FROM (SELECT f.NAME,
Count(*) AS nr,
FROM dossier d
JOIN feature f
ON f.file_id = d.id
WHERE d.system = 'AA'
AND d.id NOT IN ( 3157, 3168, 3192 )
GROUP BY f.NAME) A
CROSS JOIN (SELECT Count(*) AS Total
FROM FILE
WHERE system = 'AA'
AND id NOT IN ( 3157, 3168, 3192 )) B
Hi I have doubt in sql server
dept
+---------+--------+
| deptkey | deptno |
+---------+--------+
| 1 | 100 |
| 2 | 101 |
| 3 | -1 |
+---------+--------+
loc
+--------+-------+
| lockey | locid |
+--------+-------+
| 1 | 200 |
| 2 | 201 |
| 3 | -1 |
+--------+-------+
trans
+----+--------+-------+------+
| id | deptno | locid | Name |
+----+--------+-------+------+
| 1 | 100 | 201 | abc |
| 2 | 101 | 203 | def |
| 3 | 103 | 200 | rav |
| 4 | 105 | 204 | jai |
| 1 | 101 | 200 | kal |
| 4 | 100 | 206 | lo |
+----+--------+-------+------+
here tran deptno= dept.deptno then corresponding key values bring if not match then we need to unmatched deptno assign -1 and corresponding key need to retrive
similar tran locid=loc.locid
based on above tables I want output like below
+----+------+---------+--------+
| id | Name | deptkey | lockey |
+----+------+---------+--------+
| 1 | abc | 1 | 2 |
| 2 | def | 2 | 3 |
| 3 | rav | 3 | 1 |
| 4 | jai | 3 | 3 |
| 1 | kal | 2 | 1 |
| 4 | lo | 1 | 3 |
+----+------+---------+--------+
I tried like below query
SELECT a.[id],a.name ,b.deptkey,c.lockey
FROM [trans] a left join dept b on a.deptno=b.deptno
left join loc c on a.locid=c.locid
above query not given expected result can you please tell me how to write query to achive this task in sql server
SELECT a.[id],a.name ,
(CASE WHEN b.deptkey IS NULL THEN (select deptkey from DEPT WHERE DeptNo = -1)
ELSE b.deptkey END) AS 'deptkey',
(CASE WHEN c.lockey IS NULL THEN (select LocKey from LOC WHERE LocId = -1)
ELSE c.lockey END) AS 'lockey '
FROM [trans] a left join dept b on a.deptno=b.deptno
left join loc c on a.locid=c.locid
http://www.sqlfiddle.com/#!3/389463/2
SELECT a.[id],a.name ,b.deptkey,c.lockey
FROM [trans] a left join dept b on isnull(a.deptno,-1)=isnull(b.deptno,-1)
left join loc c on a.locid=c.locid
try with this...
SELECT
a.[id]
, a.name
, ISNULL(b.deptkey,-1) AS [deptkey]
, ISNULL(b.lockey,-1) AS [lockey]
FROM [trans] a
left join dept b
on a.deptno = b.deptno
left join loc c
on a.locid = c.locid
When the value is not found ISNULL, change the result to -1 instead of NULL. You can just change the -1 with any default value you prefer as unmatched.
OR if you want a query driven default value (get the last record as the default value). You can change your script as presented below.
SELECT
a.[id]
, a.name
, ISNULL(b.deptkey,(SELECT TOP 1 deptno from dept ORDER BY deptkey DESC)) AS [deptkey]
, ISNULL(b.lockey,(SELECT TOP 1 locid from loc ORDER BY lockey DESC)) AS [lockey]
FROM [trans] a
left join dept b
on a.deptno = b.deptno
left join loc c
on a.locid = c.locid
I have the following problem in MySQL 5.5. Here's my table.
Suppose i have a table With 'Names' with columns Rank,NAME and data in table
When i run the query it will give result as
select *from name
Rank | NAME
-------------
1 | A
1 | B
1 | C
2 | D
2 | E
2 | F
3 | G
3 | H
3 | I
Now this is of course a terribly inconvenient way to organize data, but that's how the data happened to come in (and will continue to come in).
I need to be able to throw at it a way with list of NAMES corresponding to their Respective Rank as shown below
Rank | Name | Name | Name
-----------------------------------
1 | A | B | C
2 | D | E | F
3 | G | H | I
I have query like
select
case when rank=1 then name else null end as 1,
case when rank=2 then name else null end as 2,
case when rank=3 then name else null end as 3
from name
The name with same ranks need to be brought and showed in the same row.i cant estimate the last rank will obtained by the student so i cant pass rank values manually by using 'IN' operator.Since the rank values are unpredictable i need to get them in cross tab view dynamically withh respective to their ranks.
I've tried with all kinds of dynamic crosstab-generating queries (yes, I've seen them all), but I don't have Any sucess. Please help me. Thank you!
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(rank INT NOT NULL
,name CHAR(1) NOT NULL
,PRIMARY KEY(rank,name)
);
INSERT INTO my_table VALUES
(1 ,'A'),
(1 ,'B'),
(1 ,'C'),
(2 ,'D'),
(2 ,'E'),
(2 ,'F'),
(3 ,'G'),
(3 ,'H'),
(3 ,'I');
SELECT * FROM my_table;
+------+------+
| rank | name |
+------+------+
| 1 | A |
| 1 | B |
| 1 | C |
| 2 | D |
| 2 | E |
| 2 | F |
| 3 | G |
| 3 | H |
| 3 | I |
+------+------+
SELECT x.*,COUNT(*) subrank FROM my_table x JOIN my_table y ON y.rank = x.rank AND y.name <= x.name GROUP BY x.rank,x.name;
+------+------+---------+
| rank | name | subrank |
+------+------+---------+
| 1 | A | 1 |
| 1 | B | 2 |
| 1 | C | 3 |
| 2 | D | 1 |
| 2 | E | 2 |
| 2 | F | 3 |
| 3 | G | 1 |
| 3 | H | 2 |
| 3 | I | 3 |
+------+------+---------+
SELECT rank
, MAX(CASE WHEN subrank = 1 THEN name END) name1
, MAX(CASE WHEN subrank = 2 THEN name END) name2
, MAX(CASE WHEN subrank = 3 THEN name END) name3
FROM
( SELECT x.*
, COUNT(*) subrank
FROM my_table x
JOIN my_table y
ON y.rank = x.rank
AND y.name <= x.name
GROUP
BY x.rank
, x.name
) a
GROUP
BY rank;
+------+-------+-------+-------+
| rank | name1 | name2 | name3 |
+------+-------+-------+-------+
| 1 | A | B | C |
| 2 | D | E | F |
| 3 | G | H | I |
+------+-------+-------+-------+